<!DOCTYPE html>
<!-- saved from url=(0016)http://localhost -->
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  
  <meta charset="utf-8">

  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <style>
/*!
 *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
 *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
 */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-resistance:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"}.fa-gitlab:before{content:"\f296"}.fa-wpbeginner:before{content:"\f297"}.fa-wpforms:before{content:"\f298"}.fa-envira:before{content:"\f299"}.fa-universal-access:before{content:"\f29a"}.fa-wheelchair-alt:before{content:"\f29b"}.fa-question-circle-o:before{content:"\f29c"}.fa-blind:before{content:"\f29d"}.fa-audio-description:before{content:"\f29e"}.fa-volume-control-phone:before{content:"\f2a0"}.fa-braille:before{content:"\f2a1"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asl-interpreting:before,.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-deafness:before,.fa-hard-of-hearing:before,.fa-deaf:before{content:"\f2a4"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-signing:before,.fa-sign-language:before{content:"\f2a7"}.fa-low-vision:before{content:"\f2a8"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-pied-piper:before{content:"\f2ae"}.fa-first-order:before{content:"\f2b0"}.fa-yoast:before{content:"\f2b1"}.fa-themeisle:before{content:"\f2b2"}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:"\f2b3"}.fa-fa:before,.fa-font-awesome:before{content:"\f2b4"}.fa-handshake-o:before{content:"\f2b5"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-o:before{content:"\f2b7"}.fa-linode:before{content:"\f2b8"}.fa-address-book:before{content:"\f2b9"}.fa-address-book-o:before{content:"\f2ba"}.fa-vcard:before,.fa-address-card:before{content:"\f2bb"}.fa-vcard-o:before,.fa-address-card-o:before{content:"\f2bc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-circle-o:before{content:"\f2be"}.fa-user-o:before{content:"\f2c0"}.fa-id-badge:before{content:"\f2c1"}.fa-drivers-license:before,.fa-id-card:before{content:"\f2c2"}.fa-drivers-license-o:before,.fa-id-card-o:before{content:"\f2c3"}.fa-quora:before{content:"\f2c4"}.fa-free-code-camp:before{content:"\f2c5"}.fa-telegram:before{content:"\f2c6"}.fa-thermometer-4:before,.fa-thermometer:before,.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thermometer-2:before,.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:"\f2cb"}.fa-shower:before{content:"\f2cc"}.fa-bathtub:before,.fa-s15:before,.fa-bath:before{content:"\f2cd"}.fa-podcast:before{content:"\f2ce"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-times-rectangle:before,.fa-window-close:before{content:"\f2d3"}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:"\f2d4"}.fa-bandcamp:before{content:"\f2d5"}.fa-grav:before{content:"\f2d6"}.fa-etsy:before{content:"\f2d7"}.fa-imdb:before{content:"\f2d8"}.fa-ravelry:before{content:"\f2d9"}.fa-eercast:before{content:"\f2da"}.fa-microchip:before{content:"\f2db"}.fa-snowflake-o:before{content:"\f2dc"}.fa-superpowers:before{content:"\f2dd"}.fa-wpexplorer:before{content:"\f2de"}.fa-meetup:before{content:"\f2e0"}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}

</style>

  <style>
html, body {
  color: #333;
  font-family: -apple-system, BlinkMacSystemFont,"Segoe UI", Helvetica, Helvetica, Arial, sans-serif;
  font-size: 17px;
  -webkit-font-smoothing: antialiased;
  height: 100%;
  line-height: 1.55;
  margin: 0;
  scrollbar-track-color: Whitesmoke;
  scrollbar-arrow-color: silver;
  scrollbar-base-color: #ddd;
  scrollbar-face-color: #ddd;
  -ms-overflow-style: -ms-autohiding-scrollbar !important;
}

#MainContent {
  margin: 20px 20px 20px 30px;
}


h1, h2, h3, h4, h5, h6, .byline, .content-title {
  color: #555;
  font-weight: bold;
  font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans';
  margin-top: 1.2em;
  margin-bottom: 0.4em;
}

h1 {
  font-size: 1.9em;
  padding-bottom: 10px;
  border-bottom: 1px solid #eee;
}

h2 {
  font-size: 1.55em;
}

h3 {
  font-size: 1.35em;
}

h4 {
  font-size: 1.18em;
}

h5, h6 {
  color: #656565;
  font-size: 1.09em;
}

h6 {
  color: #777;
  font-size: 1.03em;
}

table {
  margin: 20px 0;
}

th, td {
  padding: 5px 9px;
  border-bottom: 1px solid #eee;
  vertical-align: top;
}

th {
  background: #eee
}

p {
  margin: 0.5rem 0 1rem 0;
}

a {
  font-weight: 600;
  color: #337ab7;
  text-decoration: none;
}

  a:hover {
    text-decoration: underline;
  }

img {
  max-width: 100%;
}

ul, ol {
  margin: 1.1em 0;
}

li {
  margin: 0.6em 0.2em 0.6em 1em;
}

ul > li > ul > li > ul > li {
  list-style: disc;
}

ul > li > ul > li {
  list-style: square;
}
.task-list-item
{
  list-style: none;
  margin-left: -2em;
}
/* definition lists can be toggled*/
dt {
  font-size: 1.08em;
  font-weight: bold;
  text-decoration: underline;
  padding-top: 0.5em;
  cursor: pointer;
}

dd {
  margin: 0;
  padding: 0 0 0.2em 1em;
  display: none;
}

b, strong {
  font-weight: 600;
}

dt {
  font-size: 1.08em;
  font-weight: bold;
  text-decoration: underline;
  padding-top: 0.5em;
}

dd {
  margin: 0;
  padding: 0 0 0.2em 1em;
}


/* hidden display, but still part of document flow */
.hidden {
  display: none;
}

.hidden-nowidth {
  width: 0;
}

.visually-hidden {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}


@media(min-width: 1080px) {
  html, body {
    font-size: 1.06em;
  }
}



blockquote {
  background: #f5f5f5;
  color: #656565;
  border-left: 8px #aaa solid;
  border-radius: 4px;
  padding: 10px 20px;
  margin: 30px 20px;
  font-size: 1.03em;
}

  blockquote *:first-child {
    margin-top: 0;
  }

  blockquote *:last-child {
    margin-bottom: 0;
  }

hr {
  margin: 12px 0;
}

.figure .caption, figure figcaption {
  font-size: 0.8em;
  font-style: italic;
  margin-top: 0;
}

code {
  padding: 2px 5px;
  font-family: "SFMono-Regular",Consolas,"Liberation Mono",Menlo,Courier,monospace;
  border-radius: 3px;
  font-weight: 600;
  background: #eee;
  color: #555;
}

pre {
  font-family: menlo,consolas,monospace;
  font-weight: normal;
  font-size: 87%;
  line-height: 1.40;
  margin: 7px 0;
  padding: 0;
  border: 1px solid silver;
  border-radius: 5px;
  overflow-x: auto;
  max-width: 98%;
  white-space: pre;
  word-break: normal;
  word-wrap: normal;
  background: #252525;
  color: #eee;
}

pre > code {
  white-space: pre;
  padding: 0.8em !important;
  display: block;
  color: #f5f5f5 !important;
  background: transparent;
  font-weight: normal;
}

table {
  width: 100%;
  overflow: auto;
  display: block;
  border-spacing: 0;
  border-collapse: collapse;
  margin: 15px 0;
  border-color: gray;
}

td, th {
  border: 1px solid #ddd;
  padding: 6px 13px;
  display: table-cell;
  vertical-align: top;
}

th {
  font-weight: bold;
  color: white;
  background: #555;
}

tbody > tr:nth-child(even) {
  background: #eee;
}

.line-highlight {
  background: #e9f5ff !important;
}

p.line-highlight, h1.line-highlight, h2.line-highlight, h3.line-highlight, h4.line-highlight {
  border-radius: 4px;
  margin-left: -10px;
  margin-right: -10px;
  padding-left: 10px;
  padding-right: 10px;
}

code.line-highlight {
  background: #555 !important;
}



/* hidden display, but still part of document flow */
.hidden {
  display: none;
}

.hidden-nowidth {
  width: 0;
}

.visually-hidden {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}

.line-highlight {
  background: #f5f5f5;
  border-radius: 3px;
}

/* DocFx Styles*/
.CAUTION, .IMPORTANT, .INFO, .TIP, .NOTE, .WARNING
{
  padding: 0.1px 20px;
  margin: 15px 0;
  border-radius: 4px;
}
.CAUTION > h5, .IMPORTANT > h5, .INFO > h5, .TIP > h5, .NOTE > h5, .WARNING > h5 {
  color: inherit;
}
.CAUTION, .IMPORTANT {
  color: #a94442;
  background-color: #f2dede;
  border-color: #ebccd1;
}
.WARNING {
  color: #8a6d3b;
  background-color: #fcf8e3;
  border-color: #faebcc;
}
.INFO, .TIP, .NOTE {
  color: #31708f;
  background-color: #d9edf7;
  border-color: #bce8f1;
}


.hljs {
  font-size: 1em;
}

@media(min-width: 1080px) {
  html, body {
    font-size: 1.06em;
  }
}

@media print {
  pre {
    white-space: pre-wrap;
    word-break: normal;
    word-wrap: normal;
  }

    pre > code {
      white-space: pre-wrap;
      padding: 1em !important;
    }
}

</style>

  <script src="data:text/javascript;base64,LyohIGpRdWVyeSB2Mi4yLjIgfCAoYykgalF1ZXJ5IEZvdW5kYXRpb24gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8NCiFmdW5jdGlvbihhLGIpeyJvYmplY3QiPT10eXBlb2YgbW9kdWxlJiYib2JqZWN0Ij09dHlwZW9mIG1vZHVsZS5leHBvcnRzP21vZHVsZS5leHBvcnRzPWEuZG9jdW1lbnQ/YihhLCEwKTpmdW5jdGlvbihhKXtpZighYS5kb2N1bWVudCl0aHJvdyBuZXcgRXJyb3IoImpRdWVyeSByZXF1aXJlcyBhIHdpbmRvdyB3aXRoIGEgZG9jdW1lbnQiKTtyZXR1cm4gYihhKX06YihhKX0oInVuZGVmaW5lZCIhPXR5cGVvZiB3aW5kb3c/d2luZG93OnRoaXMsZnVuY3Rpb24oYSxiKXt2YXIgYz1bXSxkPWEuZG9jdW1lbnQsZT1jLnNsaWNlLGY9Yy5jb25jYXQsZz1jLnB1c2gsaD1jLmluZGV4T2YsaT17fSxqPWkudG9TdHJpbmcsaz1pLmhhc093blByb3BlcnR5LGw9e30sbT0iMi4yLjIiLG49ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbmV3IG4uZm4uaW5pdChhLGIpfSxvPS9eW1xzXHVGRUZGXHhBMF0rfFtcc1x1RkVGRlx4QTBdKyQvZyxwPS9eLW1zLS8scT0vLShbXGRhLXpdKS9naSxyPWZ1bmN0aW9uKGEsYil7cmV0dXJuIGIudG9VcHBlckNhc2UoKX07bi5mbj1uLnByb3RvdHlwZT17anF1ZXJ5Om0sY29uc3RydWN0b3I6bixzZWxlY3RvcjoiIixsZW5ndGg6MCx0b0FycmF5OmZ1bmN0aW9uKCl7cmV0dXJuIGUuY2FsbCh0aGlzKX0sZ2V0OmZ1bmN0aW9uKGEpe3JldHVybiBudWxsIT1hPzA+YT90aGlzW2ErdGhpcy5sZW5ndGhdOnRoaXNbYV06ZS5jYWxsKHRoaXMpfSxwdXNoU3RhY2s6ZnVuY3Rpb24oYSl7dmFyIGI9bi5tZXJnZSh0aGlzLmNvbnN0cnVjdG9yKCksYSk7cmV0dXJuIGIucHJldk9iamVjdD10aGlzLGIuY29udGV4dD10aGlzLmNvbnRleHQsYn0sZWFjaDpmdW5jdGlvbihhKXtyZXR1cm4gbi5lYWNoKHRoaXMsYSl9LG1hcDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5wdXNoU3RhY2sobi5tYXAodGhpcyxmdW5jdGlvbihiLGMpe3JldHVybiBhLmNhbGwoYixjLGIpfSkpfSxzbGljZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLnB1c2hTdGFjayhlLmFwcGx5KHRoaXMsYXJndW1lbnRzKSl9LGZpcnN0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZXEoMCl9LGxhc3Q6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5lcSgtMSl9LGVxOmZ1bmN0aW9uKGEpe3ZhciBiPXRoaXMubGVuZ3RoLGM9K2ErKDA+YT9iOjApO3JldHVybiB0aGlzLnB1c2hTdGFjayhjPj0wJiZiPmM/W3RoaXNbY11dOltdKX0sZW5kOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucHJldk9iamVjdHx8dGhpcy5jb25zdHJ1Y3RvcigpfSxwdXNoOmcsc29ydDpjLnNvcnQsc3BsaWNlOmMuc3BsaWNlfSxuLmV4dGVuZD1uLmZuLmV4dGVuZD1mdW5jdGlvbigpe3ZhciBhLGIsYyxkLGUsZixnPWFyZ3VtZW50c1swXXx8e30saD0xLGk9YXJndW1lbnRzLmxlbmd0aCxqPSExO2ZvcigiYm9vbGVhbiI9PXR5cGVvZiBnJiYoaj1nLGc9YXJndW1lbnRzW2hdfHx7fSxoKyspLCJvYmplY3QiPT10eXBlb2YgZ3x8bi5pc0Z1bmN0aW9uKGcpfHwoZz17fSksaD09PWkmJihnPXRoaXMsaC0tKTtpPmg7aCsrKWlmKG51bGwhPShhPWFyZ3VtZW50c1toXSkpZm9yKGIgaW4gYSljPWdbYl0sZD1hW2JdLGchPT1kJiYoaiYmZCYmKG4uaXNQbGFpbk9iamVjdChkKXx8KGU9bi5pc0FycmF5KGQpKSk/KGU/KGU9ITEsZj1jJiZuLmlzQXJyYXkoYyk/YzpbXSk6Zj1jJiZuLmlzUGxhaW5PYmplY3QoYyk/Yzp7fSxnW2JdPW4uZXh0ZW5kKGosZixkKSk6dm9pZCAwIT09ZCYmKGdbYl09ZCkpO3JldHVybiBnfSxuLmV4dGVuZCh7ZXhwYW5kbzoialF1ZXJ5IisobStNYXRoLnJhbmRvbSgpKS5yZXBsYWNlKC9cRC9nLCIiKSxpc1JlYWR5OiEwLGVycm9yOmZ1bmN0aW9uKGEpe3Rocm93IG5ldyBFcnJvcihhKX0sbm9vcDpmdW5jdGlvbigpe30saXNGdW5jdGlvbjpmdW5jdGlvbihhKXtyZXR1cm4iZnVuY3Rpb24iPT09bi50eXBlKGEpfSxpc0FycmF5OkFycmF5LmlzQXJyYXksaXNXaW5kb3c6ZnVuY3Rpb24oYSl7cmV0dXJuIG51bGwhPWEmJmE9PT1hLndpbmRvd30saXNOdW1lcmljOmZ1bmN0aW9uKGEpe3ZhciBiPWEmJmEudG9TdHJpbmcoKTtyZXR1cm4hbi5pc0FycmF5KGEpJiZiLXBhcnNlRmxvYXQoYikrMT49MH0saXNQbGFpbk9iamVjdDpmdW5jdGlvbihhKXt2YXIgYjtpZigib2JqZWN0IiE9PW4udHlwZShhKXx8YS5ub2RlVHlwZXx8bi5pc1dpbmRvdyhhKSlyZXR1cm4hMTtpZihhLmNvbnN0cnVjdG9yJiYhay5jYWxsKGEsImNvbnN0cnVjdG9yIikmJiFrLmNhbGwoYS5jb25zdHJ1Y3Rvci5wcm90b3R5cGV8fHt9LCJpc1Byb3RvdHlwZU9mIikpcmV0dXJuITE7Zm9yKGIgaW4gYSk7cmV0dXJuIHZvaWQgMD09PWJ8fGsuY2FsbChhLGIpfSxpc0VtcHR5T2JqZWN0OmZ1bmN0aW9uKGEpe3ZhciBiO2ZvcihiIGluIGEpcmV0dXJuITE7cmV0dXJuITB9LHR5cGU6ZnVuY3Rpb24oYSl7cmV0dXJuIG51bGw9PWE/YSsiIjoib2JqZWN0Ij09dHlwZW9mIGF8fCJmdW5jdGlvbiI9PXR5cGVvZiBhP2lbai5jYWxsKGEpXXx8Im9iamVjdCI6dHlwZW9mIGF9LGdsb2JhbEV2YWw6ZnVuY3Rpb24oYSl7dmFyIGIsYz1ldmFsO2E9bi50cmltKGEpLGEmJigxPT09YS5pbmRleE9mKCJ1c2Ugc3RyaWN0Iik/KGI9ZC5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKSxiLnRleHQ9YSxkLmhlYWQuYXBwZW5kQ2hpbGQoYikucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChiKSk6YyhhKSl9LGNhbWVsQ2FzZTpmdW5jdGlvbihhKXtyZXR1cm4gYS5yZXBsYWNlKHAsIm1zLSIpLnJlcGxhY2UocSxyKX0sbm9kZU5hbWU6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYS5ub2RlTmFtZSYmYS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpPT09Yi50b0xvd2VyQ2FzZSgpfSxlYWNoOmZ1bmN0aW9uKGEsYil7dmFyIGMsZD0wO2lmKHMoYSkpe2ZvcihjPWEubGVuZ3RoO2M+ZDtkKyspaWYoYi5jYWxsKGFbZF0sZCxhW2RdKT09PSExKWJyZWFrfWVsc2UgZm9yKGQgaW4gYSlpZihiLmNhbGwoYVtkXSxkLGFbZF0pPT09ITEpYnJlYWs7cmV0dXJuIGF9LHRyaW06ZnVuY3Rpb24oYSl7cmV0dXJuIG51bGw9PWE/IiI6KGErIiIpLnJlcGxhY2UobywiIil9LG1ha2VBcnJheTpmdW5jdGlvbihhLGIpe3ZhciBjPWJ8fFtdO3JldHVybiBudWxsIT1hJiYocyhPYmplY3QoYSkpP24ubWVyZ2UoYywic3RyaW5nIj09dHlwZW9mIGE/W2FdOmEpOmcuY2FsbChjLGEpKSxjfSxpbkFycmF5OmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gbnVsbD09Yj8tMTpoLmNhbGwoYixhLGMpfSxtZXJnZTpmdW5jdGlvbihhLGIpe2Zvcih2YXIgYz0rYi5sZW5ndGgsZD0wLGU9YS5sZW5ndGg7Yz5kO2QrKylhW2UrK109YltkXTtyZXR1cm4gYS5sZW5ndGg9ZSxhfSxncmVwOmZ1bmN0aW9uKGEsYixjKXtmb3IodmFyIGQsZT1bXSxmPTAsZz1hLmxlbmd0aCxoPSFjO2c+ZjtmKyspZD0hYihhW2ZdLGYpLGQhPT1oJiZlLnB1c2goYVtmXSk7cmV0dXJuIGV9LG1hcDpmdW5jdGlvbihhLGIsYyl7dmFyIGQsZSxnPTAsaD1bXTtpZihzKGEpKWZvcihkPWEubGVuZ3RoO2Q+ZztnKyspZT1iKGFbZ10sZyxjKSxudWxsIT1lJiZoLnB1c2goZSk7ZWxzZSBmb3IoZyBpbiBhKWU9YihhW2ddLGcsYyksbnVsbCE9ZSYmaC5wdXNoKGUpO3JldHVybiBmLmFwcGx5KFtdLGgpfSxndWlkOjEscHJveHk6ZnVuY3Rpb24oYSxiKXt2YXIgYyxkLGY7cmV0dXJuInN0cmluZyI9PXR5cGVvZiBiJiYoYz1hW2JdLGI9YSxhPWMpLG4uaXNGdW5jdGlvbihhKT8oZD1lLmNhbGwoYXJndW1lbnRzLDIpLGY9ZnVuY3Rpb24oKXtyZXR1cm4gYS5hcHBseShifHx0aGlzLGQuY29uY2F0KGUuY2FsbChhcmd1bWVudHMpKSl9LGYuZ3VpZD1hLmd1aWQ9YS5ndWlkfHxuLmd1aWQrKyxmKTp2b2lkIDB9LG5vdzpEYXRlLm5vdyxzdXBwb3J0Omx9KSwiZnVuY3Rpb24iPT10eXBlb2YgU3ltYm9sJiYobi5mbltTeW1ib2wuaXRlcmF0b3JdPWNbU3ltYm9sLml0ZXJhdG9yXSksbi5lYWNoKCJCb29sZWFuIE51bWJlciBTdHJpbmcgRnVuY3Rpb24gQXJyYXkgRGF0ZSBSZWdFeHAgT2JqZWN0IEVycm9yIFN5bWJvbCIuc3BsaXQoIiAiKSxmdW5jdGlvbihhLGIpe2lbIltvYmplY3QgIitiKyJdIl09Yi50b0xvd2VyQ2FzZSgpfSk7ZnVuY3Rpb24gcyhhKXt2YXIgYj0hIWEmJiJsZW5ndGgiaW4gYSYmYS5sZW5ndGgsYz1uLnR5cGUoYSk7cmV0dXJuImZ1bmN0aW9uIj09PWN8fG4uaXNXaW5kb3coYSk/ITE6ImFycmF5Ij09PWN8fDA9PT1ifHwibnVtYmVyIj09dHlwZW9mIGImJmI+MCYmYi0xIGluIGF9dmFyIHQ9ZnVuY3Rpb24oYSl7dmFyIGIsYyxkLGUsZixnLGgsaSxqLGssbCxtLG4sbyxwLHEscixzLHQsdT0ic2l6emxlIisxKm5ldyBEYXRlLHY9YS5kb2N1bWVudCx3PTAseD0wLHk9Z2EoKSx6PWdhKCksQT1nYSgpLEI9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYT09PWImJihsPSEwKSwwfSxDPTE8PDMxLEQ9e30uaGFzT3duUHJvcGVydHksRT1bXSxGPUUucG9wLEc9RS5wdXNoLEg9RS5wdXNoLEk9RS5zbGljZSxKPWZ1bmN0aW9uKGEsYil7Zm9yKHZhciBjPTAsZD1hLmxlbmd0aDtkPmM7YysrKWlmKGFbY109PT1iKXJldHVybiBjO3JldHVybi0xfSxLPSJjaGVja2VkfHNlbGVjdGVkfGFzeW5jfGF1dG9mb2N1c3xhdXRvcGxheXxjb250cm9sc3xkZWZlcnxkaXNhYmxlZHxoaWRkZW58aXNtYXB8bG9vcHxtdWx0aXBsZXxvcGVufHJlYWRvbmx5fHJlcXVpcmVkfHNjb3BlZCIsTD0iW1xceDIwXFx0XFxyXFxuXFxmXSIsTT0iKD86XFxcXC58W1xcdy1dfFteXFx4MDAtXFx4YTBdKSsiLE49IlxcWyIrTCsiKigiK00rIikoPzoiK0wrIiooWypeJHwhfl0/PSkiK0wrIiooPzonKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcInwoIitNKyIpKXwpIitMKyIqXFxdIixPPSI6KCIrTSsiKSg/OlxcKCgoJygoPzpcXFxcLnxbXlxcXFwnXSkqKSd8XCIoKD86XFxcXC58W15cXFxcXCJdKSopXCIpfCgoPzpcXFxcLnxbXlxcXFwoKVtcXF1dfCIrTisiKSopfC4qKVxcKXwpIixQPW5ldyBSZWdFeHAoTCsiKyIsImciKSxRPW5ldyBSZWdFeHAoIl4iK0wrIit8KCg/Ol58W15cXFxcXSkoPzpcXFxcLikqKSIrTCsiKyQiLCJnIiksUj1uZXcgUmVnRXhwKCJeIitMKyIqLCIrTCsiKiIpLFM9bmV3IFJlZ0V4cCgiXiIrTCsiKihbPit+XXwiK0wrIikiK0wrIioiKSxUPW5ldyBSZWdFeHAoIj0iK0wrIiooW15cXF0nXCJdKj8pIitMKyIqXFxdIiwiZyIpLFU9bmV3IFJlZ0V4cChPKSxWPW5ldyBSZWdFeHAoIl4iK00rIiQiKSxXPXtJRDpuZXcgUmVnRXhwKCJeIygiK00rIikiKSxDTEFTUzpuZXcgUmVnRXhwKCJeXFwuKCIrTSsiKSIpLFRBRzpuZXcgUmVnRXhwKCJeKCIrTSsifFsqXSkiKSxBVFRSOm5ldyBSZWdFeHAoIl4iK04pLFBTRVVETzpuZXcgUmVnRXhwKCJeIitPKSxDSElMRDpuZXcgUmVnRXhwKCJeOihvbmx5fGZpcnN0fGxhc3R8bnRofG50aC1sYXN0KS0oY2hpbGR8b2YtdHlwZSkoPzpcXCgiK0wrIiooZXZlbnxvZGR8KChbKy1dfCkoXFxkKilufCkiK0wrIiooPzooWystXXwpIitMKyIqKFxcZCspfCkpIitMKyIqXFwpfCkiLCJpIiksYm9vbDpuZXcgUmVnRXhwKCJeKD86IitLKyIpJCIsImkiKSxuZWVkc0NvbnRleHQ6bmV3IFJlZ0V4cCgiXiIrTCsiKls+K35dfDooZXZlbnxvZGR8ZXF8Z3R8bHR8bnRofGZpcnN0fGxhc3QpKD86XFwoIitMKyIqKCg/Oi1cXGQpP1xcZCopIitMKyIqXFwpfCkoPz1bXi1dfCQpIiwiaSIpfSxYPS9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbikkL2ksWT0vXmhcZCQvaSxaPS9eW157XStce1xzKlxbbmF0aXZlIFx3LywkPS9eKD86IyhbXHctXSspfChcdyspfFwuKFtcdy1dKykpJC8sXz0vWyt+XS8sYWE9Lyd8XFwvZyxiYT1uZXcgUmVnRXhwKCJcXFxcKFtcXGRhLWZdezEsNn0iK0wrIj98KCIrTCsiKXwuKSIsImlnIiksY2E9ZnVuY3Rpb24oYSxiLGMpe3ZhciBkPSIweCIrYi02NTUzNjtyZXR1cm4gZCE9PWR8fGM/YjowPmQ/U3RyaW5nLmZyb21DaGFyQ29kZShkKzY1NTM2KTpTdHJpbmcuZnJvbUNoYXJDb2RlKGQ+PjEwfDU1Mjk2LDEwMjMmZHw1NjMyMCl9LGRhPWZ1bmN0aW9uKCl7bSgpfTt0cnl7SC5hcHBseShFPUkuY2FsbCh2LmNoaWxkTm9kZXMpLHYuY2hpbGROb2RlcyksRVt2LmNoaWxkTm9kZXMubGVuZ3RoXS5ub2RlVHlwZX1jYXRjaChlYSl7SD17YXBwbHk6RS5sZW5ndGg/ZnVuY3Rpb24oYSxiKXtHLmFwcGx5KGEsSS5jYWxsKGIpKX06ZnVuY3Rpb24oYSxiKXt2YXIgYz1hLmxlbmd0aCxkPTA7d2hpbGUoYVtjKytdPWJbZCsrXSk7YS5sZW5ndGg9Yy0xfX19ZnVuY3Rpb24gZmEoYSxiLGQsZSl7dmFyIGYsaCxqLGssbCxvLHIscyx3PWImJmIub3duZXJEb2N1bWVudCx4PWI/Yi5ub2RlVHlwZTo5O2lmKGQ9ZHx8W10sInN0cmluZyIhPXR5cGVvZiBhfHwhYXx8MSE9PXgmJjkhPT14JiYxMSE9PXgpcmV0dXJuIGQ7aWYoIWUmJigoYj9iLm93bmVyRG9jdW1lbnR8fGI6dikhPT1uJiZtKGIpLGI9Ynx8bixwKSl7aWYoMTEhPT14JiYobz0kLmV4ZWMoYSkpKWlmKGY9b1sxXSl7aWYoOT09PXgpe2lmKCEoaj1iLmdldEVsZW1lbnRCeUlkKGYpKSlyZXR1cm4gZDtpZihqLmlkPT09ZilyZXR1cm4gZC5wdXNoKGopLGR9ZWxzZSBpZih3JiYoaj13LmdldEVsZW1lbnRCeUlkKGYpKSYmdChiLGopJiZqLmlkPT09ZilyZXR1cm4gZC5wdXNoKGopLGR9ZWxzZXtpZihvWzJdKXJldHVybiBILmFwcGx5KGQsYi5nZXRFbGVtZW50c0J5VGFnTmFtZShhKSksZDtpZigoZj1vWzNdKSYmYy5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lJiZiLmdldEVsZW1lbnRzQnlDbGFzc05hbWUpcmV0dXJuIEguYXBwbHkoZCxiLmdldEVsZW1lbnRzQnlDbGFzc05hbWUoZikpLGR9aWYoYy5xc2EmJiFBW2ErIiAiXSYmKCFxfHwhcS50ZXN0KGEpKSl7aWYoMSE9PXgpdz1iLHM9YTtlbHNlIGlmKCJvYmplY3QiIT09Yi5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpKXsoaz1iLmdldEF0dHJpYnV0ZSgiaWQiKSk/az1rLnJlcGxhY2UoYWEsIlxcJCYiKTpiLnNldEF0dHJpYnV0ZSgiaWQiLGs9dSkscj1nKGEpLGg9ci5sZW5ndGgsbD1WLnRlc3Qoayk/IiMiK2s6IltpZD0nIitrKyInXSI7d2hpbGUoaC0tKXJbaF09bCsiICIrcWEocltoXSk7cz1yLmpvaW4oIiwiKSx3PV8udGVzdChhKSYmb2EoYi5wYXJlbnROb2RlKXx8Yn1pZihzKXRyeXtyZXR1cm4gSC5hcHBseShkLHcucXVlcnlTZWxlY3RvckFsbChzKSksZH1jYXRjaCh5KXt9ZmluYWxseXtrPT09dSYmYi5yZW1vdmVBdHRyaWJ1dGUoImlkIil9fX1yZXR1cm4gaShhLnJlcGxhY2UoUSwiJDEiKSxiLGQsZSl9ZnVuY3Rpb24gZ2EoKXt2YXIgYT1bXTtmdW5jdGlvbiBiKGMsZSl7cmV0dXJuIGEucHVzaChjKyIgIik+ZC5jYWNoZUxlbmd0aCYmZGVsZXRlIGJbYS5zaGlmdCgpXSxiW2MrIiAiXT1lfXJldHVybiBifWZ1bmN0aW9uIGhhKGEpe3JldHVybiBhW3VdPSEwLGF9ZnVuY3Rpb24gaWEoYSl7dmFyIGI9bi5jcmVhdGVFbGVtZW50KCJkaXYiKTt0cnl7cmV0dXJuISFhKGIpfWNhdGNoKGMpe3JldHVybiExfWZpbmFsbHl7Yi5wYXJlbnROb2RlJiZiLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoYiksYj1udWxsfX1mdW5jdGlvbiBqYShhLGIpe3ZhciBjPWEuc3BsaXQoInwiKSxlPWMubGVuZ3RoO3doaWxlKGUtLSlkLmF0dHJIYW5kbGVbY1tlXV09Yn1mdW5jdGlvbiBrYShhLGIpe3ZhciBjPWImJmEsZD1jJiYxPT09YS5ub2RlVHlwZSYmMT09PWIubm9kZVR5cGUmJih+Yi5zb3VyY2VJbmRleHx8QyktKH5hLnNvdXJjZUluZGV4fHxDKTtpZihkKXJldHVybiBkO2lmKGMpd2hpbGUoYz1jLm5leHRTaWJsaW5nKWlmKGM9PT1iKXJldHVybi0xO3JldHVybiBhPzE6LTF9ZnVuY3Rpb24gbGEoYSl7cmV0dXJuIGZ1bmN0aW9uKGIpe3ZhciBjPWIubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtyZXR1cm4iaW5wdXQiPT09YyYmYi50eXBlPT09YX19ZnVuY3Rpb24gbWEoYSl7cmV0dXJuIGZ1bmN0aW9uKGIpe3ZhciBjPWIubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtyZXR1cm4oImlucHV0Ij09PWN8fCJidXR0b24iPT09YykmJmIudHlwZT09PWF9fWZ1bmN0aW9uIG5hKGEpe3JldHVybiBoYShmdW5jdGlvbihiKXtyZXR1cm4gYj0rYixoYShmdW5jdGlvbihjLGQpe3ZhciBlLGY9YShbXSxjLmxlbmd0aCxiKSxnPWYubGVuZ3RoO3doaWxlKGctLSljW2U9ZltnXV0mJihjW2VdPSEoZFtlXT1jW2VdKSl9KX0pfWZ1bmN0aW9uIG9hKGEpe3JldHVybiBhJiYidW5kZWZpbmVkIiE9dHlwZW9mIGEuZ2V0RWxlbWVudHNCeVRhZ05hbWUmJmF9Yz1mYS5zdXBwb3J0PXt9LGY9ZmEuaXNYTUw9ZnVuY3Rpb24oYSl7dmFyIGI9YSYmKGEub3duZXJEb2N1bWVudHx8YSkuZG9jdW1lbnRFbGVtZW50O3JldHVybiBiPyJIVE1MIiE9PWIubm9kZU5hbWU6ITF9LG09ZmEuc2V0RG9jdW1lbnQ9ZnVuY3Rpb24oYSl7dmFyIGIsZSxnPWE/YS5vd25lckRvY3VtZW50fHxhOnY7cmV0dXJuIGchPT1uJiY5PT09Zy5ub2RlVHlwZSYmZy5kb2N1bWVudEVsZW1lbnQ/KG49ZyxvPW4uZG9jdW1lbnRFbGVtZW50LHA9IWYobiksKGU9bi5kZWZhdWx0VmlldykmJmUudG9wIT09ZSYmKGUuYWRkRXZlbnRMaXN0ZW5lcj9lLmFkZEV2ZW50TGlzdGVuZXIoInVubG9hZCIsZGEsITEpOmUuYXR0YWNoRXZlbnQmJmUuYXR0YWNoRXZlbnQoIm9udW5sb2FkIixkYSkpLGMuYXR0cmlidXRlcz1pYShmdW5jdGlvbihhKXtyZXR1cm4gYS5jbGFzc05hbWU9ImkiLCFhLmdldEF0dHJpYnV0ZSgiY2xhc3NOYW1lIil9KSxjLmdldEVsZW1lbnRzQnlUYWdOYW1lPWlhKGZ1bmN0aW9uKGEpe3JldHVybiBhLmFwcGVuZENoaWxkKG4uY3JlYXRlQ29tbWVudCgiIikpLCFhLmdldEVsZW1lbnRzQnlUYWdOYW1lKCIqIikubGVuZ3RofSksYy5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lPVoudGVzdChuLmdldEVsZW1lbnRzQnlDbGFzc05hbWUpLGMuZ2V0QnlJZD1pYShmdW5jdGlvbihhKXtyZXR1cm4gby5hcHBlbmRDaGlsZChhKS5pZD11LCFuLmdldEVsZW1lbnRzQnlOYW1lfHwhbi5nZXRFbGVtZW50c0J5TmFtZSh1KS5sZW5ndGh9KSxjLmdldEJ5SWQ/KGQuZmluZC5JRD1mdW5jdGlvbihhLGIpe2lmKCJ1bmRlZmluZWQiIT10eXBlb2YgYi5nZXRFbGVtZW50QnlJZCYmcCl7dmFyIGM9Yi5nZXRFbGVtZW50QnlJZChhKTtyZXR1cm4gYz9bY106W119fSxkLmZpbHRlci5JRD1mdW5jdGlvbihhKXt2YXIgYj1hLnJlcGxhY2UoYmEsY2EpO3JldHVybiBmdW5jdGlvbihhKXtyZXR1cm4gYS5nZXRBdHRyaWJ1dGUoImlkIik9PT1ifX0pOihkZWxldGUgZC5maW5kLklELGQuZmlsdGVyLklEPWZ1bmN0aW9uKGEpe3ZhciBiPWEucmVwbGFjZShiYSxjYSk7cmV0dXJuIGZ1bmN0aW9uKGEpe3ZhciBjPSJ1bmRlZmluZWQiIT10eXBlb2YgYS5nZXRBdHRyaWJ1dGVOb2RlJiZhLmdldEF0dHJpYnV0ZU5vZGUoImlkIik7cmV0dXJuIGMmJmMudmFsdWU9PT1ifX0pLGQuZmluZC5UQUc9Yy5nZXRFbGVtZW50c0J5VGFnTmFtZT9mdW5jdGlvbihhLGIpe3JldHVybiJ1bmRlZmluZWQiIT10eXBlb2YgYi5nZXRFbGVtZW50c0J5VGFnTmFtZT9iLmdldEVsZW1lbnRzQnlUYWdOYW1lKGEpOmMucXNhP2IucXVlcnlTZWxlY3RvckFsbChhKTp2b2lkIDB9OmZ1bmN0aW9uKGEsYil7dmFyIGMsZD1bXSxlPTAsZj1iLmdldEVsZW1lbnRzQnlUYWdOYW1lKGEpO2lmKCIqIj09PWEpe3doaWxlKGM9ZltlKytdKTE9PT1jLm5vZGVUeXBlJiZkLnB1c2goYyk7cmV0dXJuIGR9cmV0dXJuIGZ9LGQuZmluZC5DTEFTUz1jLmdldEVsZW1lbnRzQnlDbGFzc05hbWUmJmZ1bmN0aW9uKGEsYil7cmV0dXJuInVuZGVmaW5lZCIhPXR5cGVvZiBiLmdldEVsZW1lbnRzQnlDbGFzc05hbWUmJnA/Yi5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKGEpOnZvaWQgMH0scj1bXSxxPVtdLChjLnFzYT1aLnRlc3Qobi5xdWVyeVNlbGVjdG9yQWxsKSkmJihpYShmdW5jdGlvbihhKXtvLmFwcGVuZENoaWxkKGEpLmlubmVySFRNTD0iPGEgaWQ9JyIrdSsiJz48L2E+PHNlbGVjdCBpZD0nIit1KyItXHJcXCcgbXNhbGxvd2NhcHR1cmU9Jyc+PG9wdGlvbiBzZWxlY3RlZD0nJz48L29wdGlvbj48L3NlbGVjdD4iLGEucXVlcnlTZWxlY3RvckFsbCgiW21zYWxsb3djYXB0dXJlXj0nJ10iKS5sZW5ndGgmJnEucHVzaCgiWypeJF09IitMKyIqKD86Jyd8XCJcIikiKSxhLnF1ZXJ5U2VsZWN0b3JBbGwoIltzZWxlY3RlZF0iKS5sZW5ndGh8fHEucHVzaCgiXFxbIitMKyIqKD86dmFsdWV8IitLKyIpIiksYS5xdWVyeVNlbGVjdG9yQWxsKCJbaWR+PSIrdSsiLV0iKS5sZW5ndGh8fHEucHVzaCgifj0iKSxhLnF1ZXJ5U2VsZWN0b3JBbGwoIjpjaGVja2VkIikubGVuZ3RofHxxLnB1c2goIjpjaGVja2VkIiksYS5xdWVyeVNlbGVjdG9yQWxsKCJhIyIrdSsiKyoiKS5sZW5ndGh8fHEucHVzaCgiLiMuK1srfl0iKX0pLGlhKGZ1bmN0aW9uKGEpe3ZhciBiPW4uY3JlYXRlRWxlbWVudCgiaW5wdXQiKTtiLnNldEF0dHJpYnV0ZSgidHlwZSIsImhpZGRlbiIpLGEuYXBwZW5kQ2hpbGQoYikuc2V0QXR0cmlidXRlKCJuYW1lIiwiRCIpLGEucXVlcnlTZWxlY3RvckFsbCgiW25hbWU9ZF0iKS5sZW5ndGgmJnEucHVzaCgibmFtZSIrTCsiKlsqXiR8IX5dPz0iKSxhLnF1ZXJ5U2VsZWN0b3JBbGwoIjplbmFibGVkIikubGVuZ3RofHxxLnB1c2goIjplbmFibGVkIiwiOmRpc2FibGVkIiksYS5xdWVyeVNlbGVjdG9yQWxsKCIqLDp4IikscS5wdXNoKCIsLio6Iil9KSksKGMubWF0Y2hlc1NlbGVjdG9yPVoudGVzdChzPW8ubWF0Y2hlc3x8by53ZWJraXRNYXRjaGVzU2VsZWN0b3J8fG8ubW96TWF0Y2hlc1NlbGVjdG9yfHxvLm9NYXRjaGVzU2VsZWN0b3J8fG8ubXNNYXRjaGVzU2VsZWN0b3IpKSYmaWEoZnVuY3Rpb24oYSl7Yy5kaXNjb25uZWN0ZWRNYXRjaD1zLmNhbGwoYSwiZGl2Iikscy5jYWxsKGEsIltzIT0nJ106eCIpLHIucHVzaCgiIT0iLE8pfSkscT1xLmxlbmd0aCYmbmV3IFJlZ0V4cChxLmpvaW4oInwiKSkscj1yLmxlbmd0aCYmbmV3IFJlZ0V4cChyLmpvaW4oInwiKSksYj1aLnRlc3Qoby5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiksdD1ifHxaLnRlc3Qoby5jb250YWlucyk/ZnVuY3Rpb24oYSxiKXt2YXIgYz05PT09YS5ub2RlVHlwZT9hLmRvY3VtZW50RWxlbWVudDphLGQ9YiYmYi5wYXJlbnROb2RlO3JldHVybiBhPT09ZHx8ISghZHx8MSE9PWQubm9kZVR5cGV8fCEoYy5jb250YWlucz9jLmNvbnRhaW5zKGQpOmEuY29tcGFyZURvY3VtZW50UG9zaXRpb24mJjE2JmEuY29tcGFyZURvY3VtZW50UG9zaXRpb24oZCkpKX06ZnVuY3Rpb24oYSxiKXtpZihiKXdoaWxlKGI9Yi5wYXJlbnROb2RlKWlmKGI9PT1hKXJldHVybiEwO3JldHVybiExfSxCPWI/ZnVuY3Rpb24oYSxiKXtpZihhPT09YilyZXR1cm4gbD0hMCwwO3ZhciBkPSFhLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uLSFiLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uO3JldHVybiBkP2Q6KGQ9KGEub3duZXJEb2N1bWVudHx8YSk9PT0oYi5vd25lckRvY3VtZW50fHxiKT9hLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKGIpOjEsMSZkfHwhYy5zb3J0RGV0YWNoZWQmJmIuY29tcGFyZURvY3VtZW50UG9zaXRpb24oYSk9PT1kP2E9PT1ufHxhLm93bmVyRG9jdW1lbnQ9PT12JiZ0KHYsYSk/LTE6Yj09PW58fGIub3duZXJEb2N1bWVudD09PXYmJnQodixiKT8xOms/SihrLGEpLUooayxiKTowOjQmZD8tMToxKX06ZnVuY3Rpb24oYSxiKXtpZihhPT09YilyZXR1cm4gbD0hMCwwO3ZhciBjLGQ9MCxlPWEucGFyZW50Tm9kZSxmPWIucGFyZW50Tm9kZSxnPVthXSxoPVtiXTtpZighZXx8IWYpcmV0dXJuIGE9PT1uPy0xOmI9PT1uPzE6ZT8tMTpmPzE6az9KKGssYSktSihrLGIpOjA7aWYoZT09PWYpcmV0dXJuIGthKGEsYik7Yz1hO3doaWxlKGM9Yy5wYXJlbnROb2RlKWcudW5zaGlmdChjKTtjPWI7d2hpbGUoYz1jLnBhcmVudE5vZGUpaC51bnNoaWZ0KGMpO3doaWxlKGdbZF09PT1oW2RdKWQrKztyZXR1cm4gZD9rYShnW2RdLGhbZF0pOmdbZF09PT12Py0xOmhbZF09PT12PzE6MH0sbik6bn0sZmEubWF0Y2hlcz1mdW5jdGlvbihhLGIpe3JldHVybiBmYShhLG51bGwsbnVsbCxiKX0sZmEubWF0Y2hlc1NlbGVjdG9yPWZ1bmN0aW9uKGEsYil7aWYoKGEub3duZXJEb2N1bWVudHx8YSkhPT1uJiZtKGEpLGI9Yi5yZXBsYWNlKFQsIj0nJDEnXSIpLGMubWF0Y2hlc1NlbGVjdG9yJiZwJiYhQVtiKyIgIl0mJighcnx8IXIudGVzdChiKSkmJighcXx8IXEudGVzdChiKSkpdHJ5e3ZhciBkPXMuY2FsbChhLGIpO2lmKGR8fGMuZGlzY29ubmVjdGVkTWF0Y2h8fGEuZG9jdW1lbnQmJjExIT09YS5kb2N1bWVudC5ub2RlVHlwZSlyZXR1cm4gZH1jYXRjaChlKXt9cmV0dXJuIGZhKGIsbixudWxsLFthXSkubGVuZ3RoPjB9LGZhLmNvbnRhaW5zPWZ1bmN0aW9uKGEsYil7cmV0dXJuKGEub3duZXJEb2N1bWVudHx8YSkhPT1uJiZtKGEpLHQoYSxiKX0sZmEuYXR0cj1mdW5jdGlvbihhLGIpeyhhLm93bmVyRG9jdW1lbnR8fGEpIT09biYmbShhKTt2YXIgZT1kLmF0dHJIYW5kbGVbYi50b0xvd2VyQ2FzZSgpXSxmPWUmJkQuY2FsbChkLmF0dHJIYW5kbGUsYi50b0xvd2VyQ2FzZSgpKT9lKGEsYiwhcCk6dm9pZCAwO3JldHVybiB2b2lkIDAhPT1mP2Y6Yy5hdHRyaWJ1dGVzfHwhcD9hLmdldEF0dHJpYnV0ZShiKTooZj1hLmdldEF0dHJpYnV0ZU5vZGUoYikpJiZmLnNwZWNpZmllZD9mLnZhbHVlOm51bGx9LGZhLmVycm9yPWZ1bmN0aW9uKGEpe3Rocm93IG5ldyBFcnJvcigiU3ludGF4IGVycm9yLCB1bnJlY29nbml6ZWQgZXhwcmVzc2lvbjogIithKX0sZmEudW5pcXVlU29ydD1mdW5jdGlvbihhKXt2YXIgYixkPVtdLGU9MCxmPTA7aWYobD0hYy5kZXRlY3REdXBsaWNhdGVzLGs9IWMuc29ydFN0YWJsZSYmYS5zbGljZSgwKSxhLnNvcnQoQiksbCl7d2hpbGUoYj1hW2YrK10pYj09PWFbZl0mJihlPWQucHVzaChmKSk7d2hpbGUoZS0tKWEuc3BsaWNlKGRbZV0sMSl9cmV0dXJuIGs9bnVsbCxhfSxlPWZhLmdldFRleHQ9ZnVuY3Rpb24oYSl7dmFyIGIsYz0iIixkPTAsZj1hLm5vZGVUeXBlO2lmKGYpe2lmKDE9PT1mfHw5PT09Znx8MTE9PT1mKXtpZigic3RyaW5nIj09dHlwZW9mIGEudGV4dENvbnRlbnQpcmV0dXJuIGEudGV4dENvbnRlbnQ7Zm9yKGE9YS5maXJzdENoaWxkO2E7YT1hLm5leHRTaWJsaW5nKWMrPWUoYSl9ZWxzZSBpZigzPT09Znx8ND09PWYpcmV0dXJuIGEubm9kZVZhbHVlfWVsc2Ugd2hpbGUoYj1hW2QrK10pYys9ZShiKTtyZXR1cm4gY30sZD1mYS5zZWxlY3RvcnM9e2NhY2hlTGVuZ3RoOjUwLGNyZWF0ZVBzZXVkbzpoYSxtYXRjaDpXLGF0dHJIYW5kbGU6e30sZmluZDp7fSxyZWxhdGl2ZTp7Ij4iOntkaXI6InBhcmVudE5vZGUiLGZpcnN0OiEwfSwiICI6e2RpcjoicGFyZW50Tm9kZSJ9LCIrIjp7ZGlyOiJwcmV2aW91c1NpYmxpbmciLGZpcnN0OiEwfSwifiI6e2RpcjoicHJldmlvdXNTaWJsaW5nIn19LHByZUZpbHRlcjp7QVRUUjpmdW5jdGlvbihhKXtyZXR1cm4gYVsxXT1hWzFdLnJlcGxhY2UoYmEsY2EpLGFbM109KGFbM118fGFbNF18fGFbNV18fCIiKS5yZXBsYWNlKGJhLGNhKSwifj0iPT09YVsyXSYmKGFbM109IiAiK2FbM10rIiAiKSxhLnNsaWNlKDAsNCl9LENISUxEOmZ1bmN0aW9uKGEpe3JldHVybiBhWzFdPWFbMV0udG9Mb3dlckNhc2UoKSwibnRoIj09PWFbMV0uc2xpY2UoMCwzKT8oYVszXXx8ZmEuZXJyb3IoYVswXSksYVs0XT0rKGFbNF0/YVs1XSsoYVs2XXx8MSk6MiooImV2ZW4iPT09YVszXXx8Im9kZCI9PT1hWzNdKSksYVs1XT0rKGFbN10rYVs4XXx8Im9kZCI9PT1hWzNdKSk6YVszXSYmZmEuZXJyb3IoYVswXSksYX0sUFNFVURPOmZ1bmN0aW9uKGEpe3ZhciBiLGM9IWFbNl0mJmFbMl07cmV0dXJuIFcuQ0hJTEQudGVzdChhWzBdKT9udWxsOihhWzNdP2FbMl09YVs0XXx8YVs1XXx8IiI6YyYmVS50ZXN0KGMpJiYoYj1nKGMsITApKSYmKGI9Yy5pbmRleE9mKCIpIixjLmxlbmd0aC1iKS1jLmxlbmd0aCkmJihhWzBdPWFbMF0uc2xpY2UoMCxiKSxhWzJdPWMuc2xpY2UoMCxiKSksYS5zbGljZSgwLDMpKX19LGZpbHRlcjp7VEFHOmZ1bmN0aW9uKGEpe3ZhciBiPWEucmVwbGFjZShiYSxjYSkudG9Mb3dlckNhc2UoKTtyZXR1cm4iKiI9PT1hP2Z1bmN0aW9uKCl7cmV0dXJuITB9OmZ1bmN0aW9uKGEpe3JldHVybiBhLm5vZGVOYW1lJiZhLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT1ifX0sQ0xBU1M6ZnVuY3Rpb24oYSl7dmFyIGI9eVthKyIgIl07cmV0dXJuIGJ8fChiPW5ldyBSZWdFeHAoIihefCIrTCsiKSIrYSsiKCIrTCsifCQpIikpJiZ5KGEsZnVuY3Rpb24oYSl7cmV0dXJuIGIudGVzdCgic3RyaW5nIj09dHlwZW9mIGEuY2xhc3NOYW1lJiZhLmNsYXNzTmFtZXx8InVuZGVmaW5lZCIhPXR5cGVvZiBhLmdldEF0dHJpYnV0ZSYmYS5nZXRBdHRyaWJ1dGUoImNsYXNzIil8fCIiKX0pfSxBVFRSOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gZnVuY3Rpb24oZCl7dmFyIGU9ZmEuYXR0cihkLGEpO3JldHVybiBudWxsPT1lPyIhPSI9PT1iOmI/KGUrPSIiLCI9Ij09PWI/ZT09PWM6IiE9Ij09PWI/ZSE9PWM6Il49Ij09PWI/YyYmMD09PWUuaW5kZXhPZihjKToiKj0iPT09Yj9jJiZlLmluZGV4T2YoYyk+LTE6IiQ9Ij09PWI/YyYmZS5zbGljZSgtYy5sZW5ndGgpPT09Yzoifj0iPT09Yj8oIiAiK2UucmVwbGFjZShQLCIgIikrIiAiKS5pbmRleE9mKGMpPi0xOiJ8PSI9PT1iP2U9PT1jfHxlLnNsaWNlKDAsYy5sZW5ndGgrMSk9PT1jKyItIjohMSk6ITB9fSxDSElMRDpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciBmPSJudGgiIT09YS5zbGljZSgwLDMpLGc9Imxhc3QiIT09YS5zbGljZSgtNCksaD0ib2YtdHlwZSI9PT1iO3JldHVybiAxPT09ZCYmMD09PWU/ZnVuY3Rpb24oYSl7cmV0dXJuISFhLnBhcmVudE5vZGV9OmZ1bmN0aW9uKGIsYyxpKXt2YXIgaixrLGwsbSxuLG8scD1mIT09Zz8ibmV4dFNpYmxpbmciOiJwcmV2aW91c1NpYmxpbmciLHE9Yi5wYXJlbnROb2RlLHI9aCYmYi5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLHM9IWkmJiFoLHQ9ITE7aWYocSl7aWYoZil7d2hpbGUocCl7bT1iO3doaWxlKG09bVtwXSlpZihoP20ubm9kZU5hbWUudG9Mb3dlckNhc2UoKT09PXI6MT09PW0ubm9kZVR5cGUpcmV0dXJuITE7bz1wPSJvbmx5Ij09PWEmJiFvJiYibmV4dFNpYmxpbmcifXJldHVybiEwfWlmKG89W2c/cS5maXJzdENoaWxkOnEubGFzdENoaWxkXSxnJiZzKXttPXEsbD1tW3VdfHwobVt1XT17fSksaz1sW20udW5pcXVlSURdfHwobFttLnVuaXF1ZUlEXT17fSksaj1rW2FdfHxbXSxuPWpbMF09PT13JiZqWzFdLHQ9biYmalsyXSxtPW4mJnEuY2hpbGROb2Rlc1tuXTt3aGlsZShtPSsrbiYmbSYmbVtwXXx8KHQ9bj0wKXx8by5wb3AoKSlpZigxPT09bS5ub2RlVHlwZSYmKyt0JiZtPT09Yil7a1thXT1bdyxuLHRdO2JyZWFrfX1lbHNlIGlmKHMmJihtPWIsbD1tW3VdfHwobVt1XT17fSksaz1sW20udW5pcXVlSURdfHwobFttLnVuaXF1ZUlEXT17fSksaj1rW2FdfHxbXSxuPWpbMF09PT13JiZqWzFdLHQ9biksdD09PSExKXdoaWxlKG09KytuJiZtJiZtW3BdfHwodD1uPTApfHxvLnBvcCgpKWlmKChoP20ubm9kZU5hbWUudG9Mb3dlckNhc2UoKT09PXI6MT09PW0ubm9kZVR5cGUpJiYrK3QmJihzJiYobD1tW3VdfHwobVt1XT17fSksaz1sW20udW5pcXVlSURdfHwobFttLnVuaXF1ZUlEXT17fSksa1thXT1bdyx0XSksbT09PWIpKWJyZWFrO3JldHVybiB0LT1lLHQ9PT1kfHx0JWQ9PT0wJiZ0L2Q+PTB9fX0sUFNFVURPOmZ1bmN0aW9uKGEsYil7dmFyIGMsZT1kLnBzZXVkb3NbYV18fGQuc2V0RmlsdGVyc1thLnRvTG93ZXJDYXNlKCldfHxmYS5lcnJvcigidW5zdXBwb3J0ZWQgcHNldWRvOiAiK2EpO3JldHVybiBlW3VdP2UoYik6ZS5sZW5ndGg+MT8oYz1bYSxhLCIiLGJdLGQuc2V0RmlsdGVycy5oYXNPd25Qcm9wZXJ0eShhLnRvTG93ZXJDYXNlKCkpP2hhKGZ1bmN0aW9uKGEsYyl7dmFyIGQsZj1lKGEsYiksZz1mLmxlbmd0aDt3aGlsZShnLS0pZD1KKGEsZltnXSksYVtkXT0hKGNbZF09ZltnXSl9KTpmdW5jdGlvbihhKXtyZXR1cm4gZShhLDAsYyl9KTplfX0scHNldWRvczp7bm90OmhhKGZ1bmN0aW9uKGEpe3ZhciBiPVtdLGM9W10sZD1oKGEucmVwbGFjZShRLCIkMSIpKTtyZXR1cm4gZFt1XT9oYShmdW5jdGlvbihhLGIsYyxlKXt2YXIgZixnPWQoYSxudWxsLGUsW10pLGg9YS5sZW5ndGg7d2hpbGUoaC0tKShmPWdbaF0pJiYoYVtoXT0hKGJbaF09ZikpfSk6ZnVuY3Rpb24oYSxlLGYpe3JldHVybiBiWzBdPWEsZChiLG51bGwsZixjKSxiWzBdPW51bGwsIWMucG9wKCl9fSksaGFzOmhhKGZ1bmN0aW9uKGEpe3JldHVybiBmdW5jdGlvbihiKXtyZXR1cm4gZmEoYSxiKS5sZW5ndGg+MH19KSxjb250YWluczpoYShmdW5jdGlvbihhKXtyZXR1cm4gYT1hLnJlcGxhY2UoYmEsY2EpLGZ1bmN0aW9uKGIpe3JldHVybihiLnRleHRDb250ZW50fHxiLmlubmVyVGV4dHx8ZShiKSkuaW5kZXhPZihhKT4tMX19KSxsYW5nOmhhKGZ1bmN0aW9uKGEpe3JldHVybiBWLnRlc3QoYXx8IiIpfHxmYS5lcnJvcigidW5zdXBwb3J0ZWQgbGFuZzogIithKSxhPWEucmVwbGFjZShiYSxjYSkudG9Mb3dlckNhc2UoKSxmdW5jdGlvbihiKXt2YXIgYztkbyBpZihjPXA/Yi5sYW5nOmIuZ2V0QXR0cmlidXRlKCJ4bWw6bGFuZyIpfHxiLmdldEF0dHJpYnV0ZSgibGFuZyIpKXJldHVybiBjPWMudG9Mb3dlckNhc2UoKSxjPT09YXx8MD09PWMuaW5kZXhPZihhKyItIik7d2hpbGUoKGI9Yi5wYXJlbnROb2RlKSYmMT09PWIubm9kZVR5cGUpO3JldHVybiExfX0pLHRhcmdldDpmdW5jdGlvbihiKXt2YXIgYz1hLmxvY2F0aW9uJiZhLmxvY2F0aW9uLmhhc2g7cmV0dXJuIGMmJmMuc2xpY2UoMSk9PT1iLmlkfSxyb290OmZ1bmN0aW9uKGEpe3JldHVybiBhPT09b30sZm9jdXM6ZnVuY3Rpb24oYSl7cmV0dXJuIGE9PT1uLmFjdGl2ZUVsZW1lbnQmJighbi5oYXNGb2N1c3x8bi5oYXNGb2N1cygpKSYmISEoYS50eXBlfHxhLmhyZWZ8fH5hLnRhYkluZGV4KX0sZW5hYmxlZDpmdW5jdGlvbihhKXtyZXR1cm4gYS5kaXNhYmxlZD09PSExfSxkaXNhYmxlZDpmdW5jdGlvbihhKXtyZXR1cm4gYS5kaXNhYmxlZD09PSEwfSxjaGVja2VkOmZ1bmN0aW9uKGEpe3ZhciBiPWEubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtyZXR1cm4iaW5wdXQiPT09YiYmISFhLmNoZWNrZWR8fCJvcHRpb24iPT09YiYmISFhLnNlbGVjdGVkfSxzZWxlY3RlZDpmdW5jdGlvbihhKXtyZXR1cm4gYS5wYXJlbnROb2RlJiZhLnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCxhLnNlbGVjdGVkPT09ITB9LGVtcHR5OmZ1bmN0aW9uKGEpe2ZvcihhPWEuZmlyc3RDaGlsZDthO2E9YS5uZXh0U2libGluZylpZihhLm5vZGVUeXBlPDYpcmV0dXJuITE7cmV0dXJuITB9LHBhcmVudDpmdW5jdGlvbihhKXtyZXR1cm4hZC5wc2V1ZG9zLmVtcHR5KGEpfSxoZWFkZXI6ZnVuY3Rpb24oYSl7cmV0dXJuIFkudGVzdChhLm5vZGVOYW1lKX0saW5wdXQ6ZnVuY3Rpb24oYSl7cmV0dXJuIFgudGVzdChhLm5vZGVOYW1lKX0sYnV0dG9uOmZ1bmN0aW9uKGEpe3ZhciBiPWEubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtyZXR1cm4iaW5wdXQiPT09YiYmImJ1dHRvbiI9PT1hLnR5cGV8fCJidXR0b24iPT09Yn0sdGV4dDpmdW5jdGlvbihhKXt2YXIgYjtyZXR1cm4iaW5wdXQiPT09YS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpJiYidGV4dCI9PT1hLnR5cGUmJihudWxsPT0oYj1hLmdldEF0dHJpYnV0ZSgidHlwZSIpKXx8InRleHQiPT09Yi50b0xvd2VyQ2FzZSgpKX0sZmlyc3Q6bmEoZnVuY3Rpb24oKXtyZXR1cm5bMF19KSxsYXN0Om5hKGZ1bmN0aW9uKGEsYil7cmV0dXJuW2ItMV19KSxlcTpuYShmdW5jdGlvbihhLGIsYyl7cmV0dXJuWzA+Yz9jK2I6Y119KSxldmVuOm5hKGZ1bmN0aW9uKGEsYil7Zm9yKHZhciBjPTA7Yj5jO2MrPTIpYS5wdXNoKGMpO3JldHVybiBhfSksb2RkOm5hKGZ1bmN0aW9uKGEsYil7Zm9yKHZhciBjPTE7Yj5jO2MrPTIpYS5wdXNoKGMpO3JldHVybiBhfSksbHQ6bmEoZnVuY3Rpb24oYSxiLGMpe2Zvcih2YXIgZD0wPmM/YytiOmM7LS1kPj0wOylhLnB1c2goZCk7cmV0dXJuIGF9KSxndDpuYShmdW5jdGlvbihhLGIsYyl7Zm9yKHZhciBkPTA+Yz9jK2I6YzsrK2Q8YjspYS5wdXNoKGQpO3JldHVybiBhfSl9fSxkLnBzZXVkb3MubnRoPWQucHNldWRvcy5lcTtmb3IoYiBpbntyYWRpbzohMCxjaGVja2JveDohMCxmaWxlOiEwLHBhc3N3b3JkOiEwLGltYWdlOiEwfSlkLnBzZXVkb3NbYl09bGEoYik7Zm9yKGIgaW57c3VibWl0OiEwLHJlc2V0OiEwfSlkLnBzZXVkb3NbYl09bWEoYik7ZnVuY3Rpb24gcGEoKXt9cGEucHJvdG90eXBlPWQuZmlsdGVycz1kLnBzZXVkb3MsZC5zZXRGaWx0ZXJzPW5ldyBwYSxnPWZhLnRva2VuaXplPWZ1bmN0aW9uKGEsYil7dmFyIGMsZSxmLGcsaCxpLGosaz16W2ErIiAiXTtpZihrKXJldHVybiBiPzA6ay5zbGljZSgwKTtoPWEsaT1bXSxqPWQucHJlRmlsdGVyO3doaWxlKGgpe2MmJiEoZT1SLmV4ZWMoaCkpfHwoZSYmKGg9aC5zbGljZShlWzBdLmxlbmd0aCl8fGgpLGkucHVzaChmPVtdKSksYz0hMSwoZT1TLmV4ZWMoaCkpJiYoYz1lLnNoaWZ0KCksZi5wdXNoKHt2YWx1ZTpjLHR5cGU6ZVswXS5yZXBsYWNlKFEsIiAiKX0pLGg9aC5zbGljZShjLmxlbmd0aCkpO2ZvcihnIGluIGQuZmlsdGVyKSEoZT1XW2ddLmV4ZWMoaCkpfHxqW2ddJiYhKGU9altnXShlKSl8fChjPWUuc2hpZnQoKSxmLnB1c2goe3ZhbHVlOmMsdHlwZTpnLG1hdGNoZXM6ZX0pLGg9aC5zbGljZShjLmxlbmd0aCkpO2lmKCFjKWJyZWFrfXJldHVybiBiP2gubGVuZ3RoOmg/ZmEuZXJyb3IoYSk6eihhLGkpLnNsaWNlKDApfTtmdW5jdGlvbiBxYShhKXtmb3IodmFyIGI9MCxjPWEubGVuZ3RoLGQ9IiI7Yz5iO2IrKylkKz1hW2JdLnZhbHVlO3JldHVybiBkfWZ1bmN0aW9uIHJhKGEsYixjKXt2YXIgZD1iLmRpcixlPWMmJiJwYXJlbnROb2RlIj09PWQsZj14Kys7cmV0dXJuIGIuZmlyc3Q/ZnVuY3Rpb24oYixjLGYpe3doaWxlKGI9YltkXSlpZigxPT09Yi5ub2RlVHlwZXx8ZSlyZXR1cm4gYShiLGMsZil9OmZ1bmN0aW9uKGIsYyxnKXt2YXIgaCxpLGosaz1bdyxmXTtpZihnKXt3aGlsZShiPWJbZF0paWYoKDE9PT1iLm5vZGVUeXBlfHxlKSYmYShiLGMsZykpcmV0dXJuITB9ZWxzZSB3aGlsZShiPWJbZF0paWYoMT09PWIubm9kZVR5cGV8fGUpe2lmKGo9Ylt1XXx8KGJbdV09e30pLGk9altiLnVuaXF1ZUlEXXx8KGpbYi51bmlxdWVJRF09e30pLChoPWlbZF0pJiZoWzBdPT09dyYmaFsxXT09PWYpcmV0dXJuIGtbMl09aFsyXTtpZihpW2RdPWssa1syXT1hKGIsYyxnKSlyZXR1cm4hMH19fWZ1bmN0aW9uIHNhKGEpe3JldHVybiBhLmxlbmd0aD4xP2Z1bmN0aW9uKGIsYyxkKXt2YXIgZT1hLmxlbmd0aDt3aGlsZShlLS0paWYoIWFbZV0oYixjLGQpKXJldHVybiExO3JldHVybiEwfTphWzBdfWZ1bmN0aW9uIHRhKGEsYixjKXtmb3IodmFyIGQ9MCxlPWIubGVuZ3RoO2U+ZDtkKyspZmEoYSxiW2RdLGMpO3JldHVybiBjfWZ1bmN0aW9uIHVhKGEsYixjLGQsZSl7Zm9yKHZhciBmLGc9W10saD0wLGk9YS5sZW5ndGgsaj1udWxsIT1iO2k+aDtoKyspKGY9YVtoXSkmJihjJiYhYyhmLGQsZSl8fChnLnB1c2goZiksaiYmYi5wdXNoKGgpKSk7cmV0dXJuIGd9ZnVuY3Rpb24gdmEoYSxiLGMsZCxlLGYpe3JldHVybiBkJiYhZFt1XSYmKGQ9dmEoZCkpLGUmJiFlW3VdJiYoZT12YShlLGYpKSxoYShmdW5jdGlvbihmLGcsaCxpKXt2YXIgaixrLGwsbT1bXSxuPVtdLG89Zy5sZW5ndGgscD1mfHx0YShifHwiKiIsaC5ub2RlVHlwZT9baF06aCxbXSkscT0hYXx8IWYmJmI/cDp1YShwLG0sYSxoLGkpLHI9Yz9lfHwoZj9hOm98fGQpP1tdOmc6cTtpZihjJiZjKHEscixoLGkpLGQpe2o9dWEocixuKSxkKGosW10saCxpKSxrPWoubGVuZ3RoO3doaWxlKGstLSkobD1qW2tdKSYmKHJbbltrXV09IShxW25ba11dPWwpKX1pZihmKXtpZihlfHxhKXtpZihlKXtqPVtdLGs9ci5sZW5ndGg7d2hpbGUoay0tKShsPXJba10pJiZqLnB1c2gocVtrXT1sKTtlKG51bGwscj1bXSxqLGkpfWs9ci5sZW5ndGg7d2hpbGUoay0tKShsPXJba10pJiYoaj1lP0ooZixsKTptW2tdKT4tMSYmKGZbal09IShnW2pdPWwpKX19ZWxzZSByPXVhKHI9PT1nP3Iuc3BsaWNlKG8sci5sZW5ndGgpOnIpLGU/ZShudWxsLGcscixpKTpILmFwcGx5KGcscil9KX1mdW5jdGlvbiB3YShhKXtmb3IodmFyIGIsYyxlLGY9YS5sZW5ndGgsZz1kLnJlbGF0aXZlW2FbMF0udHlwZV0saD1nfHxkLnJlbGF0aXZlWyIgIl0saT1nPzE6MCxrPXJhKGZ1bmN0aW9uKGEpe3JldHVybiBhPT09Yn0saCwhMCksbD1yYShmdW5jdGlvbihhKXtyZXR1cm4gSihiLGEpPi0xfSxoLCEwKSxtPVtmdW5jdGlvbihhLGMsZCl7dmFyIGU9IWcmJihkfHxjIT09ail8fCgoYj1jKS5ub2RlVHlwZT9rKGEsYyxkKTpsKGEsYyxkKSk7cmV0dXJuIGI9bnVsbCxlfV07Zj5pO2krKylpZihjPWQucmVsYXRpdmVbYVtpXS50eXBlXSltPVtyYShzYShtKSxjKV07ZWxzZXtpZihjPWQuZmlsdGVyW2FbaV0udHlwZV0uYXBwbHkobnVsbCxhW2ldLm1hdGNoZXMpLGNbdV0pe2ZvcihlPSsraTtmPmU7ZSsrKWlmKGQucmVsYXRpdmVbYVtlXS50eXBlXSlicmVhaztyZXR1cm4gdmEoaT4xJiZzYShtKSxpPjEmJnFhKGEuc2xpY2UoMCxpLTEpLmNvbmNhdCh7dmFsdWU6IiAiPT09YVtpLTJdLnR5cGU/IioiOiIifSkpLnJlcGxhY2UoUSwiJDEiKSxjLGU+aSYmd2EoYS5zbGljZShpLGUpKSxmPmUmJndhKGE9YS5zbGljZShlKSksZj5lJiZxYShhKSl9bS5wdXNoKGMpfXJldHVybiBzYShtKX1mdW5jdGlvbiB4YShhLGIpe3ZhciBjPWIubGVuZ3RoPjAsZT1hLmxlbmd0aD4wLGY9ZnVuY3Rpb24oZixnLGgsaSxrKXt2YXIgbCxvLHEscj0wLHM9IjAiLHQ9ZiYmW10sdT1bXSx2PWoseD1mfHxlJiZkLmZpbmQuVEFHKCIqIixrKSx5PXcrPW51bGw9PXY/MTpNYXRoLnJhbmRvbSgpfHwuMSx6PXgubGVuZ3RoO2ZvcihrJiYoaj1nPT09bnx8Z3x8ayk7cyE9PXomJm51bGwhPShsPXhbc10pO3MrKyl7aWYoZSYmbCl7bz0wLGd8fGwub3duZXJEb2N1bWVudD09PW58fChtKGwpLGg9IXApO3doaWxlKHE9YVtvKytdKWlmKHEobCxnfHxuLGgpKXtpLnB1c2gobCk7YnJlYWt9ayYmKHc9eSl9YyYmKChsPSFxJiZsKSYmci0tLGYmJnQucHVzaChsKSl9aWYocis9cyxjJiZzIT09cil7bz0wO3doaWxlKHE9YltvKytdKXEodCx1LGcsaCk7aWYoZil7aWYocj4wKXdoaWxlKHMtLSl0W3NdfHx1W3NdfHwodVtzXT1GLmNhbGwoaSkpO3U9dWEodSl9SC5hcHBseShpLHUpLGsmJiFmJiZ1Lmxlbmd0aD4wJiZyK2IubGVuZ3RoPjEmJmZhLnVuaXF1ZVNvcnQoaSl9cmV0dXJuIGsmJih3PXksaj12KSx0fTtyZXR1cm4gYz9oYShmKTpmfXJldHVybiBoPWZhLmNvbXBpbGU9ZnVuY3Rpb24oYSxiKXt2YXIgYyxkPVtdLGU9W10sZj1BW2ErIiAiXTtpZighZil7Ynx8KGI9ZyhhKSksYz1iLmxlbmd0aDt3aGlsZShjLS0pZj13YShiW2NdKSxmW3VdP2QucHVzaChmKTplLnB1c2goZik7Zj1BKGEseGEoZSxkKSksZi5zZWxlY3Rvcj1hfXJldHVybiBmfSxpPWZhLnNlbGVjdD1mdW5jdGlvbihhLGIsZSxmKXt2YXIgaSxqLGssbCxtLG49ImZ1bmN0aW9uIj09dHlwZW9mIGEmJmEsbz0hZiYmZyhhPW4uc2VsZWN0b3J8fGEpO2lmKGU9ZXx8W10sMT09PW8ubGVuZ3RoKXtpZihqPW9bMF09b1swXS5zbGljZSgwKSxqLmxlbmd0aD4yJiYiSUQiPT09KGs9alswXSkudHlwZSYmYy5nZXRCeUlkJiY5PT09Yi5ub2RlVHlwZSYmcCYmZC5yZWxhdGl2ZVtqWzFdLnR5cGVdKXtpZihiPShkLmZpbmQuSUQoay5tYXRjaGVzWzBdLnJlcGxhY2UoYmEsY2EpLGIpfHxbXSlbMF0sIWIpcmV0dXJuIGU7biYmKGI9Yi5wYXJlbnROb2RlKSxhPWEuc2xpY2Uoai5zaGlmdCgpLnZhbHVlLmxlbmd0aCl9aT1XLm5lZWRzQ29udGV4dC50ZXN0KGEpPzA6ai5sZW5ndGg7d2hpbGUoaS0tKXtpZihrPWpbaV0sZC5yZWxhdGl2ZVtsPWsudHlwZV0pYnJlYWs7aWYoKG09ZC5maW5kW2xdKSYmKGY9bShrLm1hdGNoZXNbMF0ucmVwbGFjZShiYSxjYSksXy50ZXN0KGpbMF0udHlwZSkmJm9hKGIucGFyZW50Tm9kZSl8fGIpKSl7aWYoai5zcGxpY2UoaSwxKSxhPWYubGVuZ3RoJiZxYShqKSwhYSlyZXR1cm4gSC5hcHBseShlLGYpLGU7YnJlYWt9fX1yZXR1cm4obnx8aChhLG8pKShmLGIsIXAsZSwhYnx8Xy50ZXN0KGEpJiZvYShiLnBhcmVudE5vZGUpfHxiKSxlfSxjLnNvcnRTdGFibGU9dS5zcGxpdCgiIikuc29ydChCKS5qb2luKCIiKT09PXUsYy5kZXRlY3REdXBsaWNhdGVzPSEhbCxtKCksYy5zb3J0RGV0YWNoZWQ9aWEoZnVuY3Rpb24oYSl7cmV0dXJuIDEmYS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihuLmNyZWF0ZUVsZW1lbnQoImRpdiIpKX0pLGlhKGZ1bmN0aW9uKGEpe3JldHVybiBhLmlubmVySFRNTD0iPGEgaHJlZj0nIyc+PC9hPiIsIiMiPT09YS5maXJzdENoaWxkLmdldEF0dHJpYnV0ZSgiaHJlZiIpfSl8fGphKCJ0eXBlfGhyZWZ8aGVpZ2h0fHdpZHRoIixmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGM/dm9pZCAwOmEuZ2V0QXR0cmlidXRlKGIsInR5cGUiPT09Yi50b0xvd2VyQ2FzZSgpPzE6Mil9KSxjLmF0dHJpYnV0ZXMmJmlhKGZ1bmN0aW9uKGEpe3JldHVybiBhLmlubmVySFRNTD0iPGlucHV0Lz4iLGEuZmlyc3RDaGlsZC5zZXRBdHRyaWJ1dGUoInZhbHVlIiwiIiksIiI9PT1hLmZpcnN0Q2hpbGQuZ2V0QXR0cmlidXRlKCJ2YWx1ZSIpfSl8fGphKCJ2YWx1ZSIsZnVuY3Rpb24oYSxiLGMpe3JldHVybiBjfHwiaW5wdXQiIT09YS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpP3ZvaWQgMDphLmRlZmF1bHRWYWx1ZX0pLGlhKGZ1bmN0aW9uKGEpe3JldHVybiBudWxsPT1hLmdldEF0dHJpYnV0ZSgiZGlzYWJsZWQiKX0pfHxqYShLLGZ1bmN0aW9uKGEsYixjKXt2YXIgZDtyZXR1cm4gYz92b2lkIDA6YVtiXT09PSEwP2IudG9Mb3dlckNhc2UoKTooZD1hLmdldEF0dHJpYnV0ZU5vZGUoYikpJiZkLnNwZWNpZmllZD9kLnZhbHVlOm51bGx9KSxmYX0oYSk7bi5maW5kPXQsbi5leHByPXQuc2VsZWN0b3JzLG4uZXhwclsiOiJdPW4uZXhwci5wc2V1ZG9zLG4udW5pcXVlU29ydD1uLnVuaXF1ZT10LnVuaXF1ZVNvcnQsbi50ZXh0PXQuZ2V0VGV4dCxuLmlzWE1MRG9jPXQuaXNYTUwsbi5jb250YWlucz10LmNvbnRhaW5zO3ZhciB1PWZ1bmN0aW9uKGEsYixjKXt2YXIgZD1bXSxlPXZvaWQgMCE9PWM7d2hpbGUoKGE9YVtiXSkmJjkhPT1hLm5vZGVUeXBlKWlmKDE9PT1hLm5vZGVUeXBlKXtpZihlJiZuKGEpLmlzKGMpKWJyZWFrO2QucHVzaChhKX1yZXR1cm4gZH0sdj1mdW5jdGlvbihhLGIpe2Zvcih2YXIgYz1bXTthO2E9YS5uZXh0U2libGluZykxPT09YS5ub2RlVHlwZSYmYSE9PWImJmMucHVzaChhKTtyZXR1cm4gY30sdz1uLmV4cHIubWF0Y2gubmVlZHNDb250ZXh0LHg9L148KFtcdy1dKylccypcLz8+KD86PFwvXDE+fCkkLyx5PS9eLlteOiNcW1wuLF0qJC87ZnVuY3Rpb24geihhLGIsYyl7aWYobi5pc0Z1bmN0aW9uKGIpKXJldHVybiBuLmdyZXAoYSxmdW5jdGlvbihhLGQpe3JldHVybiEhYi5jYWxsKGEsZCxhKSE9PWN9KTtpZihiLm5vZGVUeXBlKXJldHVybiBuLmdyZXAoYSxmdW5jdGlvbihhKXtyZXR1cm4gYT09PWIhPT1jfSk7aWYoInN0cmluZyI9PXR5cGVvZiBiKXtpZih5LnRlc3QoYikpcmV0dXJuIG4uZmlsdGVyKGIsYSxjKTtiPW4uZmlsdGVyKGIsYSl9cmV0dXJuIG4uZ3JlcChhLGZ1bmN0aW9uKGEpe3JldHVybiBoLmNhbGwoYixhKT4tMSE9PWN9KX1uLmZpbHRlcj1mdW5jdGlvbihhLGIsYyl7dmFyIGQ9YlswXTtyZXR1cm4gYyYmKGE9Ijpub3QoIithKyIpIiksMT09PWIubGVuZ3RoJiYxPT09ZC5ub2RlVHlwZT9uLmZpbmQubWF0Y2hlc1NlbGVjdG9yKGQsYSk/W2RdOltdOm4uZmluZC5tYXRjaGVzKGEsbi5ncmVwKGIsZnVuY3Rpb24oYSl7cmV0dXJuIDE9PT1hLm5vZGVUeXBlfSkpfSxuLmZuLmV4dGVuZCh7ZmluZDpmdW5jdGlvbihhKXt2YXIgYixjPXRoaXMubGVuZ3RoLGQ9W10sZT10aGlzO2lmKCJzdHJpbmciIT10eXBlb2YgYSlyZXR1cm4gdGhpcy5wdXNoU3RhY2sobihhKS5maWx0ZXIoZnVuY3Rpb24oKXtmb3IoYj0wO2M+YjtiKyspaWYobi5jb250YWlucyhlW2JdLHRoaXMpKXJldHVybiEwfSkpO2ZvcihiPTA7Yz5iO2IrKyluLmZpbmQoYSxlW2JdLGQpO3JldHVybiBkPXRoaXMucHVzaFN0YWNrKGM+MT9uLnVuaXF1ZShkKTpkKSxkLnNlbGVjdG9yPXRoaXMuc2VsZWN0b3I/dGhpcy5zZWxlY3RvcisiICIrYTphLGR9LGZpbHRlcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5wdXNoU3RhY2soeih0aGlzLGF8fFtdLCExKSl9LG5vdDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5wdXNoU3RhY2soeih0aGlzLGF8fFtdLCEwKSl9LGlzOmZ1bmN0aW9uKGEpe3JldHVybiEheih0aGlzLCJzdHJpbmciPT10eXBlb2YgYSYmdy50ZXN0KGEpP24oYSk6YXx8W10sITEpLmxlbmd0aH19KTt2YXIgQSxCPS9eKD86XHMqKDxbXHdcV10rPilbXj5dKnwjKFtcdy1dKikpJC8sQz1uLmZuLmluaXQ9ZnVuY3Rpb24oYSxiLGMpe3ZhciBlLGY7aWYoIWEpcmV0dXJuIHRoaXM7aWYoYz1jfHxBLCJzdHJpbmciPT10eXBlb2YgYSl7aWYoZT0iPCI9PT1hWzBdJiYiPiI9PT1hW2EubGVuZ3RoLTFdJiZhLmxlbmd0aD49Mz9bbnVsbCxhLG51bGxdOkIuZXhlYyhhKSwhZXx8IWVbMV0mJmIpcmV0dXJuIWJ8fGIuanF1ZXJ5PyhifHxjKS5maW5kKGEpOnRoaXMuY29uc3RydWN0b3IoYikuZmluZChhKTtpZihlWzFdKXtpZihiPWIgaW5zdGFuY2VvZiBuP2JbMF06YixuLm1lcmdlKHRoaXMsbi5wYXJzZUhUTUwoZVsxXSxiJiZiLm5vZGVUeXBlP2Iub3duZXJEb2N1bWVudHx8YjpkLCEwKSkseC50ZXN0KGVbMV0pJiZuLmlzUGxhaW5PYmplY3QoYikpZm9yKGUgaW4gYiluLmlzRnVuY3Rpb24odGhpc1tlXSk/dGhpc1tlXShiW2VdKTp0aGlzLmF0dHIoZSxiW2VdKTtyZXR1cm4gdGhpc31yZXR1cm4gZj1kLmdldEVsZW1lbnRCeUlkKGVbMl0pLGYmJmYucGFyZW50Tm9kZSYmKHRoaXMubGVuZ3RoPTEsdGhpc1swXT1mKSx0aGlzLmNvbnRleHQ9ZCx0aGlzLnNlbGVjdG9yPWEsdGhpc31yZXR1cm4gYS5ub2RlVHlwZT8odGhpcy5jb250ZXh0PXRoaXNbMF09YSx0aGlzLmxlbmd0aD0xLHRoaXMpOm4uaXNGdW5jdGlvbihhKT92b2lkIDAhPT1jLnJlYWR5P2MucmVhZHkoYSk6YShuKToodm9pZCAwIT09YS5zZWxlY3RvciYmKHRoaXMuc2VsZWN0b3I9YS5zZWxlY3Rvcix0aGlzLmNvbnRleHQ9YS5jb250ZXh0KSxuLm1ha2VBcnJheShhLHRoaXMpKX07Qy5wcm90b3R5cGU9bi5mbixBPW4oZCk7dmFyIEQ9L14oPzpwYXJlbnRzfHByZXYoPzpVbnRpbHxBbGwpKS8sRT17Y2hpbGRyZW46ITAsY29udGVudHM6ITAsbmV4dDohMCxwcmV2OiEwfTtuLmZuLmV4dGVuZCh7aGFzOmZ1bmN0aW9uKGEpe3ZhciBiPW4oYSx0aGlzKSxjPWIubGVuZ3RoO3JldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbigpe2Zvcih2YXIgYT0wO2M+YTthKyspaWYobi5jb250YWlucyh0aGlzLGJbYV0pKXJldHVybiEwfSl9LGNsb3Nlc3Q6ZnVuY3Rpb24oYSxiKXtmb3IodmFyIGMsZD0wLGU9dGhpcy5sZW5ndGgsZj1bXSxnPXcudGVzdChhKXx8InN0cmluZyIhPXR5cGVvZiBhP24oYSxifHx0aGlzLmNvbnRleHQpOjA7ZT5kO2QrKylmb3IoYz10aGlzW2RdO2MmJmMhPT1iO2M9Yy5wYXJlbnROb2RlKWlmKGMubm9kZVR5cGU8MTEmJihnP2cuaW5kZXgoYyk+LTE6MT09PWMubm9kZVR5cGUmJm4uZmluZC5tYXRjaGVzU2VsZWN0b3IoYyxhKSkpe2YucHVzaChjKTticmVha31yZXR1cm4gdGhpcy5wdXNoU3RhY2soZi5sZW5ndGg+MT9uLnVuaXF1ZVNvcnQoZik6Zil9LGluZGV4OmZ1bmN0aW9uKGEpe3JldHVybiBhPyJzdHJpbmciPT10eXBlb2YgYT9oLmNhbGwobihhKSx0aGlzWzBdKTpoLmNhbGwodGhpcyxhLmpxdWVyeT9hWzBdOmEpOnRoaXNbMF0mJnRoaXNbMF0ucGFyZW50Tm9kZT90aGlzLmZpcnN0KCkucHJldkFsbCgpLmxlbmd0aDotMX0sYWRkOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMucHVzaFN0YWNrKG4udW5pcXVlU29ydChuLm1lcmdlKHRoaXMuZ2V0KCksbihhLGIpKSkpfSxhZGRCYWNrOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmFkZChudWxsPT1hP3RoaXMucHJldk9iamVjdDp0aGlzLnByZXZPYmplY3QuZmlsdGVyKGEpKX19KTtmdW5jdGlvbiBGKGEsYil7d2hpbGUoKGE9YVtiXSkmJjEhPT1hLm5vZGVUeXBlKTtyZXR1cm4gYX1uLmVhY2goe3BhcmVudDpmdW5jdGlvbihhKXt2YXIgYj1hLnBhcmVudE5vZGU7cmV0dXJuIGImJjExIT09Yi5ub2RlVHlwZT9iOm51bGx9LHBhcmVudHM6ZnVuY3Rpb24oYSl7cmV0dXJuIHUoYSwicGFyZW50Tm9kZSIpfSxwYXJlbnRzVW50aWw6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiB1KGEsInBhcmVudE5vZGUiLGMpfSxuZXh0OmZ1bmN0aW9uKGEpe3JldHVybiBGKGEsIm5leHRTaWJsaW5nIil9LHByZXY6ZnVuY3Rpb24oYSl7cmV0dXJuIEYoYSwicHJldmlvdXNTaWJsaW5nIil9LG5leHRBbGw6ZnVuY3Rpb24oYSl7cmV0dXJuIHUoYSwibmV4dFNpYmxpbmciKX0scHJldkFsbDpmdW5jdGlvbihhKXtyZXR1cm4gdShhLCJwcmV2aW91c1NpYmxpbmciKX0sbmV4dFVudGlsOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gdShhLCJuZXh0U2libGluZyIsYyl9LHByZXZVbnRpbDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIHUoYSwicHJldmlvdXNTaWJsaW5nIixjKX0sc2libGluZ3M6ZnVuY3Rpb24oYSl7cmV0dXJuIHYoKGEucGFyZW50Tm9kZXx8e30pLmZpcnN0Q2hpbGQsYSl9LGNoaWxkcmVuOmZ1bmN0aW9uKGEpe3JldHVybiB2KGEuZmlyc3RDaGlsZCl9LGNvbnRlbnRzOmZ1bmN0aW9uKGEpe3JldHVybiBhLmNvbnRlbnREb2N1bWVudHx8bi5tZXJnZShbXSxhLmNoaWxkTm9kZXMpfX0sZnVuY3Rpb24oYSxiKXtuLmZuW2FdPWZ1bmN0aW9uKGMsZCl7dmFyIGU9bi5tYXAodGhpcyxiLGMpO3JldHVybiJVbnRpbCIhPT1hLnNsaWNlKC01KSYmKGQ9YyksZCYmInN0cmluZyI9PXR5cGVvZiBkJiYoZT1uLmZpbHRlcihkLGUpKSx0aGlzLmxlbmd0aD4xJiYoRVthXXx8bi51bmlxdWVTb3J0KGUpLEQudGVzdChhKSYmZS5yZXZlcnNlKCkpLHRoaXMucHVzaFN0YWNrKGUpfX0pO3ZhciBHPS9cUysvZztmdW5jdGlvbiBIKGEpe3ZhciBiPXt9O3JldHVybiBuLmVhY2goYS5tYXRjaChHKXx8W10sZnVuY3Rpb24oYSxjKXtiW2NdPSEwfSksYn1uLkNhbGxiYWNrcz1mdW5jdGlvbihhKXthPSJzdHJpbmciPT10eXBlb2YgYT9IKGEpOm4uZXh0ZW5kKHt9LGEpO3ZhciBiLGMsZCxlLGY9W10sZz1bXSxoPS0xLGk9ZnVuY3Rpb24oKXtmb3IoZT1hLm9uY2UsZD1iPSEwO2cubGVuZ3RoO2g9LTEpe2M9Zy5zaGlmdCgpO3doaWxlKCsraDxmLmxlbmd0aClmW2hdLmFwcGx5KGNbMF0sY1sxXSk9PT0hMSYmYS5zdG9wT25GYWxzZSYmKGg9Zi5sZW5ndGgsYz0hMSl9YS5tZW1vcnl8fChjPSExKSxiPSExLGUmJihmPWM/W106IiIpfSxqPXthZGQ6ZnVuY3Rpb24oKXtyZXR1cm4gZiYmKGMmJiFiJiYoaD1mLmxlbmd0aC0xLGcucHVzaChjKSksZnVuY3Rpb24gZChiKXtuLmVhY2goYixmdW5jdGlvbihiLGMpe24uaXNGdW5jdGlvbihjKT9hLnVuaXF1ZSYmai5oYXMoYyl8fGYucHVzaChjKTpjJiZjLmxlbmd0aCYmInN0cmluZyIhPT1uLnR5cGUoYykmJmQoYyl9KX0oYXJndW1lbnRzKSxjJiYhYiYmaSgpKSx0aGlzfSxyZW1vdmU6ZnVuY3Rpb24oKXtyZXR1cm4gbi5lYWNoKGFyZ3VtZW50cyxmdW5jdGlvbihhLGIpe3ZhciBjO3doaWxlKChjPW4uaW5BcnJheShiLGYsYykpPi0xKWYuc3BsaWNlKGMsMSksaD49YyYmaC0tfSksdGhpc30saGFzOmZ1bmN0aW9uKGEpe3JldHVybiBhP24uaW5BcnJheShhLGYpPi0xOmYubGVuZ3RoPjB9LGVtcHR5OmZ1bmN0aW9uKCl7cmV0dXJuIGYmJihmPVtdKSx0aGlzfSxkaXNhYmxlOmZ1bmN0aW9uKCl7cmV0dXJuIGU9Zz1bXSxmPWM9IiIsdGhpc30sZGlzYWJsZWQ6ZnVuY3Rpb24oKXtyZXR1cm4hZn0sbG9jazpmdW5jdGlvbigpe3JldHVybiBlPWc9W10sY3x8KGY9Yz0iIiksdGhpc30sbG9ja2VkOmZ1bmN0aW9uKCl7cmV0dXJuISFlfSxmaXJlV2l0aDpmdW5jdGlvbihhLGMpe3JldHVybiBlfHwoYz1jfHxbXSxjPVthLGMuc2xpY2U/Yy5zbGljZSgpOmNdLGcucHVzaChjKSxifHxpKCkpLHRoaXN9LGZpcmU6ZnVuY3Rpb24oKXtyZXR1cm4gai5maXJlV2l0aCh0aGlzLGFyZ3VtZW50cyksdGhpc30sZmlyZWQ6ZnVuY3Rpb24oKXtyZXR1cm4hIWR9fTtyZXR1cm4gan0sbi5leHRlbmQoe0RlZmVycmVkOmZ1bmN0aW9uKGEpe3ZhciBiPVtbInJlc29sdmUiLCJkb25lIixuLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwicmVzb2x2ZWQiXSxbInJlamVjdCIsImZhaWwiLG4uQ2FsbGJhY2tzKCJvbmNlIG1lbW9yeSIpLCJyZWplY3RlZCJdLFsibm90aWZ5IiwicHJvZ3Jlc3MiLG4uQ2FsbGJhY2tzKCJtZW1vcnkiKV1dLGM9InBlbmRpbmciLGQ9e3N0YXRlOmZ1bmN0aW9uKCl7cmV0dXJuIGN9LGFsd2F5czpmdW5jdGlvbigpe3JldHVybiBlLmRvbmUoYXJndW1lbnRzKS5mYWlsKGFyZ3VtZW50cyksdGhpc30sdGhlbjpmdW5jdGlvbigpe3ZhciBhPWFyZ3VtZW50cztyZXR1cm4gbi5EZWZlcnJlZChmdW5jdGlvbihjKXtuLmVhY2goYixmdW5jdGlvbihiLGYpe3ZhciBnPW4uaXNGdW5jdGlvbihhW2JdKSYmYVtiXTtlW2ZbMV1dKGZ1bmN0aW9uKCl7dmFyIGE9ZyYmZy5hcHBseSh0aGlzLGFyZ3VtZW50cyk7YSYmbi5pc0Z1bmN0aW9uKGEucHJvbWlzZSk/YS5wcm9taXNlKCkucHJvZ3Jlc3MoYy5ub3RpZnkpLmRvbmUoYy5yZXNvbHZlKS5mYWlsKGMucmVqZWN0KTpjW2ZbMF0rIldpdGgiXSh0aGlzPT09ZD9jLnByb21pc2UoKTp0aGlzLGc/W2FdOmFyZ3VtZW50cyl9KX0pLGE9bnVsbH0pLnByb21pc2UoKX0scHJvbWlzZTpmdW5jdGlvbihhKXtyZXR1cm4gbnVsbCE9YT9uLmV4dGVuZChhLGQpOmR9fSxlPXt9O3JldHVybiBkLnBpcGU9ZC50aGVuLG4uZWFjaChiLGZ1bmN0aW9uKGEsZil7dmFyIGc9ZlsyXSxoPWZbM107ZFtmWzFdXT1nLmFkZCxoJiZnLmFkZChmdW5jdGlvbigpe2M9aH0sYlsxXmFdWzJdLmRpc2FibGUsYlsyXVsyXS5sb2NrKSxlW2ZbMF1dPWZ1bmN0aW9uKCl7cmV0dXJuIGVbZlswXSsiV2l0aCJdKHRoaXM9PT1lP2Q6dGhpcyxhcmd1bWVudHMpLHRoaXN9LGVbZlswXSsiV2l0aCJdPWcuZmlyZVdpdGh9KSxkLnByb21pc2UoZSksYSYmYS5jYWxsKGUsZSksZX0sd2hlbjpmdW5jdGlvbihhKXt2YXIgYj0wLGM9ZS5jYWxsKGFyZ3VtZW50cyksZD1jLmxlbmd0aCxmPTEhPT1kfHxhJiZuLmlzRnVuY3Rpb24oYS5wcm9taXNlKT9kOjAsZz0xPT09Zj9hOm4uRGVmZXJyZWQoKSxoPWZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gZnVuY3Rpb24oZCl7YlthXT10aGlzLGNbYV09YXJndW1lbnRzLmxlbmd0aD4xP2UuY2FsbChhcmd1bWVudHMpOmQsYz09PWk/Zy5ub3RpZnlXaXRoKGIsYyk6LS1mfHxnLnJlc29sdmVXaXRoKGIsYyl9fSxpLGosaztpZihkPjEpZm9yKGk9bmV3IEFycmF5KGQpLGo9bmV3IEFycmF5KGQpLGs9bmV3IEFycmF5KGQpO2Q+YjtiKyspY1tiXSYmbi5pc0Z1bmN0aW9uKGNbYl0ucHJvbWlzZSk/Y1tiXS5wcm9taXNlKCkucHJvZ3Jlc3MoaChiLGosaSkpLmRvbmUoaChiLGssYykpLmZhaWwoZy5yZWplY3QpOi0tZjtyZXR1cm4gZnx8Zy5yZXNvbHZlV2l0aChrLGMpLGcucHJvbWlzZSgpfX0pO3ZhciBJO24uZm4ucmVhZHk9ZnVuY3Rpb24oYSl7cmV0dXJuIG4ucmVhZHkucHJvbWlzZSgpLmRvbmUoYSksdGhpc30sbi5leHRlbmQoe2lzUmVhZHk6ITEscmVhZHlXYWl0OjEsaG9sZFJlYWR5OmZ1bmN0aW9uKGEpe2E/bi5yZWFkeVdhaXQrKzpuLnJlYWR5KCEwKX0scmVhZHk6ZnVuY3Rpb24oYSl7KGE9PT0hMD8tLW4ucmVhZHlXYWl0Om4uaXNSZWFkeSl8fChuLmlzUmVhZHk9ITAsYSE9PSEwJiYtLW4ucmVhZHlXYWl0PjB8fChJLnJlc29sdmVXaXRoKGQsW25dKSxuLmZuLnRyaWdnZXJIYW5kbGVyJiYobihkKS50cmlnZ2VySGFuZGxlcigicmVhZHkiKSxuKGQpLm9mZigicmVhZHkiKSkpKX19KTtmdW5jdGlvbiBKKCl7ZC5yZW1vdmVFdmVudExpc3RlbmVyKCJET01Db250ZW50TG9hZGVkIixKKSxhLnJlbW92ZUV2ZW50TGlzdGVuZXIoImxvYWQiLEopLG4ucmVhZHkoKX1uLnJlYWR5LnByb21pc2U9ZnVuY3Rpb24oYil7cmV0dXJuIEl8fChJPW4uRGVmZXJyZWQoKSwiY29tcGxldGUiPT09ZC5yZWFkeVN0YXRlfHwibG9hZGluZyIhPT1kLnJlYWR5U3RhdGUmJiFkLmRvY3VtZW50RWxlbWVudC5kb1Njcm9sbD9hLnNldFRpbWVvdXQobi5yZWFkeSk6KGQuYWRkRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsSiksYS5hZGRFdmVudExpc3RlbmVyKCJsb2FkIixKKSkpLEkucHJvbWlzZShiKX0sbi5yZWFkeS5wcm9taXNlKCk7dmFyIEs9ZnVuY3Rpb24oYSxiLGMsZCxlLGYsZyl7dmFyIGg9MCxpPWEubGVuZ3RoLGo9bnVsbD09YztpZigib2JqZWN0Ij09PW4udHlwZShjKSl7ZT0hMDtmb3IoaCBpbiBjKUsoYSxiLGgsY1toXSwhMCxmLGcpfWVsc2UgaWYodm9pZCAwIT09ZCYmKGU9ITAsbi5pc0Z1bmN0aW9uKGQpfHwoZz0hMCksaiYmKGc/KGIuY2FsbChhLGQpLGI9bnVsbCk6KGo9YixiPWZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gai5jYWxsKG4oYSksYyl9KSksYikpZm9yKDtpPmg7aCsrKWIoYVtoXSxjLGc/ZDpkLmNhbGwoYVtoXSxoLGIoYVtoXSxjKSkpO3JldHVybiBlP2E6aj9iLmNhbGwoYSk6aT9iKGFbMF0sYyk6Zn0sTD1mdW5jdGlvbihhKXtyZXR1cm4gMT09PWEubm9kZVR5cGV8fDk9PT1hLm5vZGVUeXBlfHwhK2Eubm9kZVR5cGV9O2Z1bmN0aW9uIE0oKXt0aGlzLmV4cGFuZG89bi5leHBhbmRvK00udWlkKyt9TS51aWQ9MSxNLnByb3RvdHlwZT17cmVnaXN0ZXI6ZnVuY3Rpb24oYSxiKXt2YXIgYz1ifHx7fTtyZXR1cm4gYS5ub2RlVHlwZT9hW3RoaXMuZXhwYW5kb109YzpPYmplY3QuZGVmaW5lUHJvcGVydHkoYSx0aGlzLmV4cGFuZG8se3ZhbHVlOmMsd3JpdGFibGU6ITAsY29uZmlndXJhYmxlOiEwfSksYVt0aGlzLmV4cGFuZG9dfSxjYWNoZTpmdW5jdGlvbihhKXtpZighTChhKSlyZXR1cm57fTt2YXIgYj1hW3RoaXMuZXhwYW5kb107cmV0dXJuIGJ8fChiPXt9LEwoYSkmJihhLm5vZGVUeXBlP2FbdGhpcy5leHBhbmRvXT1iOk9iamVjdC5kZWZpbmVQcm9wZXJ0eShhLHRoaXMuZXhwYW5kbyx7dmFsdWU6Yixjb25maWd1cmFibGU6ITB9KSkpLGJ9LHNldDpmdW5jdGlvbihhLGIsYyl7dmFyIGQsZT10aGlzLmNhY2hlKGEpO2lmKCJzdHJpbmciPT10eXBlb2YgYillW2JdPWM7ZWxzZSBmb3IoZCBpbiBiKWVbZF09YltkXTtyZXR1cm4gZX0sZ2V0OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHZvaWQgMD09PWI/dGhpcy5jYWNoZShhKTphW3RoaXMuZXhwYW5kb10mJmFbdGhpcy5leHBhbmRvXVtiXX0sYWNjZXNzOmZ1bmN0aW9uKGEsYixjKXt2YXIgZDtyZXR1cm4gdm9pZCAwPT09Ynx8YiYmInN0cmluZyI9PXR5cGVvZiBiJiZ2b2lkIDA9PT1jPyhkPXRoaXMuZ2V0KGEsYiksdm9pZCAwIT09ZD9kOnRoaXMuZ2V0KGEsbi5jYW1lbENhc2UoYikpKToodGhpcy5zZXQoYSxiLGMpLHZvaWQgMCE9PWM/YzpiKX0scmVtb3ZlOmZ1bmN0aW9uKGEsYil7dmFyIGMsZCxlLGY9YVt0aGlzLmV4cGFuZG9dO2lmKHZvaWQgMCE9PWYpe2lmKHZvaWQgMD09PWIpdGhpcy5yZWdpc3RlcihhKTtlbHNle24uaXNBcnJheShiKT9kPWIuY29uY2F0KGIubWFwKG4uY2FtZWxDYXNlKSk6KGU9bi5jYW1lbENhc2UoYiksYiBpbiBmP2Q9W2IsZV06KGQ9ZSxkPWQgaW4gZj9bZF06ZC5tYXRjaChHKXx8W10pKSxjPWQubGVuZ3RoO3doaWxlKGMtLSlkZWxldGUgZltkW2NdXX0odm9pZCAwPT09Ynx8bi5pc0VtcHR5T2JqZWN0KGYpKSYmKGEubm9kZVR5cGU/YVt0aGlzLmV4cGFuZG9dPXZvaWQgMDpkZWxldGUgYVt0aGlzLmV4cGFuZG9dKX19LGhhc0RhdGE6ZnVuY3Rpb24oYSl7dmFyIGI9YVt0aGlzLmV4cGFuZG9dO3JldHVybiB2b2lkIDAhPT1iJiYhbi5pc0VtcHR5T2JqZWN0KGIpfX07dmFyIE49bmV3IE0sTz1uZXcgTSxQPS9eKD86XHtbXHdcV10qXH18XFtbXHdcV10qXF0pJC8sUT0vW0EtWl0vZztmdW5jdGlvbiBSKGEsYixjKXt2YXIgZDtpZih2b2lkIDA9PT1jJiYxPT09YS5ub2RlVHlwZSlpZihkPSJkYXRhLSIrYi5yZXBsYWNlKFEsIi0kJiIpLnRvTG93ZXJDYXNlKCksYz1hLmdldEF0dHJpYnV0ZShkKSwic3RyaW5nIj09dHlwZW9mIGMpe3RyeXtjPSJ0cnVlIj09PWM/ITA6ImZhbHNlIj09PWM/ITE6Im51bGwiPT09Yz9udWxsOitjKyIiPT09Yz8rYzpQLnRlc3QoYyk/bi5wYXJzZUpTT04oYyk6YzsNCn1jYXRjaChlKXt9Ty5zZXQoYSxiLGMpfWVsc2UgYz12b2lkIDA7cmV0dXJuIGN9bi5leHRlbmQoe2hhc0RhdGE6ZnVuY3Rpb24oYSl7cmV0dXJuIE8uaGFzRGF0YShhKXx8Ti5oYXNEYXRhKGEpfSxkYXRhOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gTy5hY2Nlc3MoYSxiLGMpfSxyZW1vdmVEYXRhOmZ1bmN0aW9uKGEsYil7Ty5yZW1vdmUoYSxiKX0sX2RhdGE6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBOLmFjY2VzcyhhLGIsYyl9LF9yZW1vdmVEYXRhOmZ1bmN0aW9uKGEsYil7Ti5yZW1vdmUoYSxiKX19KSxuLmZuLmV4dGVuZCh7ZGF0YTpmdW5jdGlvbihhLGIpe3ZhciBjLGQsZSxmPXRoaXNbMF0sZz1mJiZmLmF0dHJpYnV0ZXM7aWYodm9pZCAwPT09YSl7aWYodGhpcy5sZW5ndGgmJihlPU8uZ2V0KGYpLDE9PT1mLm5vZGVUeXBlJiYhTi5nZXQoZiwiaGFzRGF0YUF0dHJzIikpKXtjPWcubGVuZ3RoO3doaWxlKGMtLSlnW2NdJiYoZD1nW2NdLm5hbWUsMD09PWQuaW5kZXhPZigiZGF0YS0iKSYmKGQ9bi5jYW1lbENhc2UoZC5zbGljZSg1KSksUihmLGQsZVtkXSkpKTtOLnNldChmLCJoYXNEYXRhQXR0cnMiLCEwKX1yZXR1cm4gZX1yZXR1cm4ib2JqZWN0Ij09dHlwZW9mIGE/dGhpcy5lYWNoKGZ1bmN0aW9uKCl7Ty5zZXQodGhpcyxhKX0pOksodGhpcyxmdW5jdGlvbihiKXt2YXIgYyxkO2lmKGYmJnZvaWQgMD09PWIpe2lmKGM9Ty5nZXQoZixhKXx8Ty5nZXQoZixhLnJlcGxhY2UoUSwiLSQmIikudG9Mb3dlckNhc2UoKSksdm9pZCAwIT09YylyZXR1cm4gYztpZihkPW4uY2FtZWxDYXNlKGEpLGM9Ty5nZXQoZixkKSx2b2lkIDAhPT1jKXJldHVybiBjO2lmKGM9UihmLGQsdm9pZCAwKSx2b2lkIDAhPT1jKXJldHVybiBjfWVsc2UgZD1uLmNhbWVsQ2FzZShhKSx0aGlzLmVhY2goZnVuY3Rpb24oKXt2YXIgYz1PLmdldCh0aGlzLGQpO08uc2V0KHRoaXMsZCxiKSxhLmluZGV4T2YoIi0iKT4tMSYmdm9pZCAwIT09YyYmTy5zZXQodGhpcyxhLGIpfSl9LG51bGwsYixhcmd1bWVudHMubGVuZ3RoPjEsbnVsbCwhMCl9LHJlbW92ZURhdGE6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe08ucmVtb3ZlKHRoaXMsYSl9KX19KSxuLmV4dGVuZCh7cXVldWU6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkO3JldHVybiBhPyhiPShifHwiZngiKSsicXVldWUiLGQ9Ti5nZXQoYSxiKSxjJiYoIWR8fG4uaXNBcnJheShjKT9kPU4uYWNjZXNzKGEsYixuLm1ha2VBcnJheShjKSk6ZC5wdXNoKGMpKSxkfHxbXSk6dm9pZCAwfSxkZXF1ZXVlOmZ1bmN0aW9uKGEsYil7Yj1ifHwiZngiO3ZhciBjPW4ucXVldWUoYSxiKSxkPWMubGVuZ3RoLGU9Yy5zaGlmdCgpLGY9bi5fcXVldWVIb29rcyhhLGIpLGc9ZnVuY3Rpb24oKXtuLmRlcXVldWUoYSxiKX07ImlucHJvZ3Jlc3MiPT09ZSYmKGU9Yy5zaGlmdCgpLGQtLSksZSYmKCJmeCI9PT1iJiZjLnVuc2hpZnQoImlucHJvZ3Jlc3MiKSxkZWxldGUgZi5zdG9wLGUuY2FsbChhLGcsZikpLCFkJiZmJiZmLmVtcHR5LmZpcmUoKX0sX3F1ZXVlSG9va3M6ZnVuY3Rpb24oYSxiKXt2YXIgYz1iKyJxdWV1ZUhvb2tzIjtyZXR1cm4gTi5nZXQoYSxjKXx8Ti5hY2Nlc3MoYSxjLHtlbXB0eTpuLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKS5hZGQoZnVuY3Rpb24oKXtOLnJlbW92ZShhLFtiKyJxdWV1ZSIsY10pfSl9KX19KSxuLmZuLmV4dGVuZCh7cXVldWU6ZnVuY3Rpb24oYSxiKXt2YXIgYz0yO3JldHVybiJzdHJpbmciIT10eXBlb2YgYSYmKGI9YSxhPSJmeCIsYy0tKSxhcmd1bWVudHMubGVuZ3RoPGM/bi5xdWV1ZSh0aGlzWzBdLGEpOnZvaWQgMD09PWI/dGhpczp0aGlzLmVhY2goZnVuY3Rpb24oKXt2YXIgYz1uLnF1ZXVlKHRoaXMsYSxiKTtuLl9xdWV1ZUhvb2tzKHRoaXMsYSksImZ4Ij09PWEmJiJpbnByb2dyZXNzIiE9PWNbMF0mJm4uZGVxdWV1ZSh0aGlzLGEpfSl9LGRlcXVldWU6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe24uZGVxdWV1ZSh0aGlzLGEpfSl9LGNsZWFyUXVldWU6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMucXVldWUoYXx8ImZ4IixbXSl9LHByb21pc2U6ZnVuY3Rpb24oYSxiKXt2YXIgYyxkPTEsZT1uLkRlZmVycmVkKCksZj10aGlzLGc9dGhpcy5sZW5ndGgsaD1mdW5jdGlvbigpey0tZHx8ZS5yZXNvbHZlV2l0aChmLFtmXSl9OyJzdHJpbmciIT10eXBlb2YgYSYmKGI9YSxhPXZvaWQgMCksYT1hfHwiZngiO3doaWxlKGctLSljPU4uZ2V0KGZbZ10sYSsicXVldWVIb29rcyIpLGMmJmMuZW1wdHkmJihkKyssYy5lbXB0eS5hZGQoaCkpO3JldHVybiBoKCksZS5wcm9taXNlKGIpfX0pO3ZhciBTPS9bKy1dPyg/OlxkKlwufClcZCsoPzpbZUVdWystXT9cZCt8KS8uc291cmNlLFQ9bmV3IFJlZ0V4cCgiXig/OihbKy1dKT18KSgiK1MrIikoW2EteiVdKikkIiwiaSIpLFU9WyJUb3AiLCJSaWdodCIsIkJvdHRvbSIsIkxlZnQiXSxWPWZ1bmN0aW9uKGEsYil7cmV0dXJuIGE9Ynx8YSwibm9uZSI9PT1uLmNzcyhhLCJkaXNwbGF5Iil8fCFuLmNvbnRhaW5zKGEub3duZXJEb2N1bWVudCxhKX07ZnVuY3Rpb24gVyhhLGIsYyxkKXt2YXIgZSxmPTEsZz0yMCxoPWQ/ZnVuY3Rpb24oKXtyZXR1cm4gZC5jdXIoKX06ZnVuY3Rpb24oKXtyZXR1cm4gbi5jc3MoYSxiLCIiKX0saT1oKCksaj1jJiZjWzNdfHwobi5jc3NOdW1iZXJbYl0/IiI6InB4Iiksaz0obi5jc3NOdW1iZXJbYl18fCJweCIhPT1qJiYraSkmJlQuZXhlYyhuLmNzcyhhLGIpKTtpZihrJiZrWzNdIT09ail7aj1qfHxrWzNdLGM9Y3x8W10saz0raXx8MTtkbyBmPWZ8fCIuNSIsay89ZixuLnN0eWxlKGEsYixrK2opO3doaWxlKGYhPT0oZj1oKCkvaSkmJjEhPT1mJiYtLWcpfXJldHVybiBjJiYoaz0ra3x8K2l8fDAsZT1jWzFdP2srKGNbMV0rMSkqY1syXTorY1syXSxkJiYoZC51bml0PWosZC5zdGFydD1rLGQuZW5kPWUpKSxlfXZhciBYPS9eKD86Y2hlY2tib3h8cmFkaW8pJC9pLFk9LzwoW1x3Oi1dKykvLFo9L14kfFwvKD86amF2YXxlY21hKXNjcmlwdC9pLCQ9e29wdGlvbjpbMSwiPHNlbGVjdCBtdWx0aXBsZT0nbXVsdGlwbGUnPiIsIjwvc2VsZWN0PiJdLHRoZWFkOlsxLCI8dGFibGU+IiwiPC90YWJsZT4iXSxjb2w6WzIsIjx0YWJsZT48Y29sZ3JvdXA+IiwiPC9jb2xncm91cD48L3RhYmxlPiJdLHRyOlsyLCI8dGFibGU+PHRib2R5PiIsIjwvdGJvZHk+PC90YWJsZT4iXSx0ZDpbMywiPHRhYmxlPjx0Ym9keT48dHI+IiwiPC90cj48L3Rib2R5PjwvdGFibGU+Il0sX2RlZmF1bHQ6WzAsIiIsIiJdfTskLm9wdGdyb3VwPSQub3B0aW9uLCQudGJvZHk9JC50Zm9vdD0kLmNvbGdyb3VwPSQuY2FwdGlvbj0kLnRoZWFkLCQudGg9JC50ZDtmdW5jdGlvbiBfKGEsYil7dmFyIGM9InVuZGVmaW5lZCIhPXR5cGVvZiBhLmdldEVsZW1lbnRzQnlUYWdOYW1lP2EuZ2V0RWxlbWVudHNCeVRhZ05hbWUoYnx8IioiKToidW5kZWZpbmVkIiE9dHlwZW9mIGEucXVlcnlTZWxlY3RvckFsbD9hLnF1ZXJ5U2VsZWN0b3JBbGwoYnx8IioiKTpbXTtyZXR1cm4gdm9pZCAwPT09Ynx8YiYmbi5ub2RlTmFtZShhLGIpP24ubWVyZ2UoW2FdLGMpOmN9ZnVuY3Rpb24gYWEoYSxiKXtmb3IodmFyIGM9MCxkPWEubGVuZ3RoO2Q+YztjKyspTi5zZXQoYVtjXSwiZ2xvYmFsRXZhbCIsIWJ8fE4uZ2V0KGJbY10sImdsb2JhbEV2YWwiKSl9dmFyIGJhPS88fCYjP1x3KzsvO2Z1bmN0aW9uIGNhKGEsYixjLGQsZSl7Zm9yKHZhciBmLGcsaCxpLGosayxsPWIuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLG09W10sbz0wLHA9YS5sZW5ndGg7cD5vO28rKylpZihmPWFbb10sZnx8MD09PWYpaWYoIm9iamVjdCI9PT1uLnR5cGUoZikpbi5tZXJnZShtLGYubm9kZVR5cGU/W2ZdOmYpO2Vsc2UgaWYoYmEudGVzdChmKSl7Zz1nfHxsLmFwcGVuZENoaWxkKGIuY3JlYXRlRWxlbWVudCgiZGl2IikpLGg9KFkuZXhlYyhmKXx8WyIiLCIiXSlbMV0udG9Mb3dlckNhc2UoKSxpPSRbaF18fCQuX2RlZmF1bHQsZy5pbm5lckhUTUw9aVsxXStuLmh0bWxQcmVmaWx0ZXIoZikraVsyXSxrPWlbMF07d2hpbGUoay0tKWc9Zy5sYXN0Q2hpbGQ7bi5tZXJnZShtLGcuY2hpbGROb2RlcyksZz1sLmZpcnN0Q2hpbGQsZy50ZXh0Q29udGVudD0iIn1lbHNlIG0ucHVzaChiLmNyZWF0ZVRleHROb2RlKGYpKTtsLnRleHRDb250ZW50PSIiLG89MDt3aGlsZShmPW1bbysrXSlpZihkJiZuLmluQXJyYXkoZixkKT4tMSllJiZlLnB1c2goZik7ZWxzZSBpZihqPW4uY29udGFpbnMoZi5vd25lckRvY3VtZW50LGYpLGc9XyhsLmFwcGVuZENoaWxkKGYpLCJzY3JpcHQiKSxqJiZhYShnKSxjKXtrPTA7d2hpbGUoZj1nW2srK10pWi50ZXN0KGYudHlwZXx8IiIpJiZjLnB1c2goZil9cmV0dXJuIGx9IWZ1bmN0aW9uKCl7dmFyIGE9ZC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksYj1hLmFwcGVuZENoaWxkKGQuY3JlYXRlRWxlbWVudCgiZGl2IikpLGM9ZC5jcmVhdGVFbGVtZW50KCJpbnB1dCIpO2Muc2V0QXR0cmlidXRlKCJ0eXBlIiwicmFkaW8iKSxjLnNldEF0dHJpYnV0ZSgiY2hlY2tlZCIsImNoZWNrZWQiKSxjLnNldEF0dHJpYnV0ZSgibmFtZSIsInQiKSxiLmFwcGVuZENoaWxkKGMpLGwuY2hlY2tDbG9uZT1iLmNsb25lTm9kZSghMCkuY2xvbmVOb2RlKCEwKS5sYXN0Q2hpbGQuY2hlY2tlZCxiLmlubmVySFRNTD0iPHRleHRhcmVhPng8L3RleHRhcmVhPiIsbC5ub0Nsb25lQ2hlY2tlZD0hIWIuY2xvbmVOb2RlKCEwKS5sYXN0Q2hpbGQuZGVmYXVsdFZhbHVlfSgpO3ZhciBkYT0vXmtleS8sZWE9L14oPzptb3VzZXxwb2ludGVyfGNvbnRleHRtZW51fGRyYWd8ZHJvcCl8Y2xpY2svLGZhPS9eKFteLl0qKSg/OlwuKC4rKXwpLztmdW5jdGlvbiBnYSgpe3JldHVybiEwfWZ1bmN0aW9uIGhhKCl7cmV0dXJuITF9ZnVuY3Rpb24gaWEoKXt0cnl7cmV0dXJuIGQuYWN0aXZlRWxlbWVudH1jYXRjaChhKXt9fWZ1bmN0aW9uIGphKGEsYixjLGQsZSxmKXt2YXIgZyxoO2lmKCJvYmplY3QiPT10eXBlb2YgYil7InN0cmluZyIhPXR5cGVvZiBjJiYoZD1kfHxjLGM9dm9pZCAwKTtmb3IoaCBpbiBiKWphKGEsaCxjLGQsYltoXSxmKTtyZXR1cm4gYX1pZihudWxsPT1kJiZudWxsPT1lPyhlPWMsZD1jPXZvaWQgMCk6bnVsbD09ZSYmKCJzdHJpbmciPT10eXBlb2YgYz8oZT1kLGQ9dm9pZCAwKTooZT1kLGQ9YyxjPXZvaWQgMCkpLGU9PT0hMSllPWhhO2Vsc2UgaWYoIWUpcmV0dXJuIGE7cmV0dXJuIDE9PT1mJiYoZz1lLGU9ZnVuY3Rpb24oYSl7cmV0dXJuIG4oKS5vZmYoYSksZy5hcHBseSh0aGlzLGFyZ3VtZW50cyl9LGUuZ3VpZD1nLmd1aWR8fChnLmd1aWQ9bi5ndWlkKyspKSxhLmVhY2goZnVuY3Rpb24oKXtuLmV2ZW50LmFkZCh0aGlzLGIsZSxkLGMpfSl9bi5ldmVudD17Z2xvYmFsOnt9LGFkZDpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciBmLGcsaCxpLGosayxsLG0sbyxwLHEscj1OLmdldChhKTtpZihyKXtjLmhhbmRsZXImJihmPWMsYz1mLmhhbmRsZXIsZT1mLnNlbGVjdG9yKSxjLmd1aWR8fChjLmd1aWQ9bi5ndWlkKyspLChpPXIuZXZlbnRzKXx8KGk9ci5ldmVudHM9e30pLChnPXIuaGFuZGxlKXx8KGc9ci5oYW5kbGU9ZnVuY3Rpb24oYil7cmV0dXJuInVuZGVmaW5lZCIhPXR5cGVvZiBuJiZuLmV2ZW50LnRyaWdnZXJlZCE9PWIudHlwZT9uLmV2ZW50LmRpc3BhdGNoLmFwcGx5KGEsYXJndW1lbnRzKTp2b2lkIDB9KSxiPShifHwiIikubWF0Y2goRyl8fFsiIl0saj1iLmxlbmd0aDt3aGlsZShqLS0paD1mYS5leGVjKGJbal0pfHxbXSxvPXE9aFsxXSxwPShoWzJdfHwiIikuc3BsaXQoIi4iKS5zb3J0KCksbyYmKGw9bi5ldmVudC5zcGVjaWFsW29dfHx7fSxvPShlP2wuZGVsZWdhdGVUeXBlOmwuYmluZFR5cGUpfHxvLGw9bi5ldmVudC5zcGVjaWFsW29dfHx7fSxrPW4uZXh0ZW5kKHt0eXBlOm8sb3JpZ1R5cGU6cSxkYXRhOmQsaGFuZGxlcjpjLGd1aWQ6Yy5ndWlkLHNlbGVjdG9yOmUsbmVlZHNDb250ZXh0OmUmJm4uZXhwci5tYXRjaC5uZWVkc0NvbnRleHQudGVzdChlKSxuYW1lc3BhY2U6cC5qb2luKCIuIil9LGYpLChtPWlbb10pfHwobT1pW29dPVtdLG0uZGVsZWdhdGVDb3VudD0wLGwuc2V0dXAmJmwuc2V0dXAuY2FsbChhLGQscCxnKSE9PSExfHxhLmFkZEV2ZW50TGlzdGVuZXImJmEuYWRkRXZlbnRMaXN0ZW5lcihvLGcpKSxsLmFkZCYmKGwuYWRkLmNhbGwoYSxrKSxrLmhhbmRsZXIuZ3VpZHx8KGsuaGFuZGxlci5ndWlkPWMuZ3VpZCkpLGU/bS5zcGxpY2UobS5kZWxlZ2F0ZUNvdW50KyssMCxrKTptLnB1c2goayksbi5ldmVudC5nbG9iYWxbb109ITApfX0scmVtb3ZlOmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIGYsZyxoLGksaixrLGwsbSxvLHAscSxyPU4uaGFzRGF0YShhKSYmTi5nZXQoYSk7aWYociYmKGk9ci5ldmVudHMpKXtiPShifHwiIikubWF0Y2goRyl8fFsiIl0saj1iLmxlbmd0aDt3aGlsZShqLS0paWYoaD1mYS5leGVjKGJbal0pfHxbXSxvPXE9aFsxXSxwPShoWzJdfHwiIikuc3BsaXQoIi4iKS5zb3J0KCksbyl7bD1uLmV2ZW50LnNwZWNpYWxbb118fHt9LG89KGQ/bC5kZWxlZ2F0ZVR5cGU6bC5iaW5kVHlwZSl8fG8sbT1pW29dfHxbXSxoPWhbMl0mJm5ldyBSZWdFeHAoIihefFxcLikiK3Auam9pbigiXFwuKD86LipcXC58KSIpKyIoXFwufCQpIiksZz1mPW0ubGVuZ3RoO3doaWxlKGYtLSlrPW1bZl0sIWUmJnEhPT1rLm9yaWdUeXBlfHxjJiZjLmd1aWQhPT1rLmd1aWR8fGgmJiFoLnRlc3Qoay5uYW1lc3BhY2UpfHxkJiZkIT09ay5zZWxlY3RvciYmKCIqKiIhPT1kfHwhay5zZWxlY3Rvcil8fChtLnNwbGljZShmLDEpLGsuc2VsZWN0b3ImJm0uZGVsZWdhdGVDb3VudC0tLGwucmVtb3ZlJiZsLnJlbW92ZS5jYWxsKGEsaykpO2cmJiFtLmxlbmd0aCYmKGwudGVhcmRvd24mJmwudGVhcmRvd24uY2FsbChhLHAsci5oYW5kbGUpIT09ITF8fG4ucmVtb3ZlRXZlbnQoYSxvLHIuaGFuZGxlKSxkZWxldGUgaVtvXSl9ZWxzZSBmb3IobyBpbiBpKW4uZXZlbnQucmVtb3ZlKGEsbytiW2pdLGMsZCwhMCk7bi5pc0VtcHR5T2JqZWN0KGkpJiZOLnJlbW92ZShhLCJoYW5kbGUgZXZlbnRzIil9fSxkaXNwYXRjaDpmdW5jdGlvbihhKXthPW4uZXZlbnQuZml4KGEpO3ZhciBiLGMsZCxmLGcsaD1bXSxpPWUuY2FsbChhcmd1bWVudHMpLGo9KE4uZ2V0KHRoaXMsImV2ZW50cyIpfHx7fSlbYS50eXBlXXx8W10saz1uLmV2ZW50LnNwZWNpYWxbYS50eXBlXXx8e307aWYoaVswXT1hLGEuZGVsZWdhdGVUYXJnZXQ9dGhpcywhay5wcmVEaXNwYXRjaHx8ay5wcmVEaXNwYXRjaC5jYWxsKHRoaXMsYSkhPT0hMSl7aD1uLmV2ZW50LmhhbmRsZXJzLmNhbGwodGhpcyxhLGopLGI9MDt3aGlsZSgoZj1oW2IrK10pJiYhYS5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpKXthLmN1cnJlbnRUYXJnZXQ9Zi5lbGVtLGM9MDt3aGlsZSgoZz1mLmhhbmRsZXJzW2MrK10pJiYhYS5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCgpKWEucm5hbWVzcGFjZSYmIWEucm5hbWVzcGFjZS50ZXN0KGcubmFtZXNwYWNlKXx8KGEuaGFuZGxlT2JqPWcsYS5kYXRhPWcuZGF0YSxkPSgobi5ldmVudC5zcGVjaWFsW2cub3JpZ1R5cGVdfHx7fSkuaGFuZGxlfHxnLmhhbmRsZXIpLmFwcGx5KGYuZWxlbSxpKSx2b2lkIDAhPT1kJiYoYS5yZXN1bHQ9ZCk9PT0hMSYmKGEucHJldmVudERlZmF1bHQoKSxhLnN0b3BQcm9wYWdhdGlvbigpKSl9cmV0dXJuIGsucG9zdERpc3BhdGNoJiZrLnBvc3REaXNwYXRjaC5jYWxsKHRoaXMsYSksYS5yZXN1bHR9fSxoYW5kbGVyczpmdW5jdGlvbihhLGIpe3ZhciBjLGQsZSxmLGc9W10saD1iLmRlbGVnYXRlQ291bnQsaT1hLnRhcmdldDtpZihoJiZpLm5vZGVUeXBlJiYoImNsaWNrIiE9PWEudHlwZXx8aXNOYU4oYS5idXR0b24pfHxhLmJ1dHRvbjwxKSlmb3IoO2khPT10aGlzO2k9aS5wYXJlbnROb2RlfHx0aGlzKWlmKDE9PT1pLm5vZGVUeXBlJiYoaS5kaXNhYmxlZCE9PSEwfHwiY2xpY2siIT09YS50eXBlKSl7Zm9yKGQ9W10sYz0wO2g+YztjKyspZj1iW2NdLGU9Zi5zZWxlY3RvcisiICIsdm9pZCAwPT09ZFtlXSYmKGRbZV09Zi5uZWVkc0NvbnRleHQ/bihlLHRoaXMpLmluZGV4KGkpPi0xOm4uZmluZChlLHRoaXMsbnVsbCxbaV0pLmxlbmd0aCksZFtlXSYmZC5wdXNoKGYpO2QubGVuZ3RoJiZnLnB1c2goe2VsZW06aSxoYW5kbGVyczpkfSl9cmV0dXJuIGg8Yi5sZW5ndGgmJmcucHVzaCh7ZWxlbTp0aGlzLGhhbmRsZXJzOmIuc2xpY2UoaCl9KSxnfSxwcm9wczoiYWx0S2V5IGJ1YmJsZXMgY2FuY2VsYWJsZSBjdHJsS2V5IGN1cnJlbnRUYXJnZXQgZGV0YWlsIGV2ZW50UGhhc2UgbWV0YUtleSByZWxhdGVkVGFyZ2V0IHNoaWZ0S2V5IHRhcmdldCB0aW1lU3RhbXAgdmlldyB3aGljaCIuc3BsaXQoIiAiKSxmaXhIb29rczp7fSxrZXlIb29rczp7cHJvcHM6ImNoYXIgY2hhckNvZGUga2V5IGtleUNvZGUiLnNwbGl0KCIgIiksZmlsdGVyOmZ1bmN0aW9uKGEsYil7cmV0dXJuIG51bGw9PWEud2hpY2gmJihhLndoaWNoPW51bGwhPWIuY2hhckNvZGU/Yi5jaGFyQ29kZTpiLmtleUNvZGUpLGF9fSxtb3VzZUhvb2tzOntwcm9wczoiYnV0dG9uIGJ1dHRvbnMgY2xpZW50WCBjbGllbnRZIG9mZnNldFggb2Zmc2V0WSBwYWdlWCBwYWdlWSBzY3JlZW5YIHNjcmVlblkgdG9FbGVtZW50Ii5zcGxpdCgiICIpLGZpbHRlcjpmdW5jdGlvbihhLGIpe3ZhciBjLGUsZixnPWIuYnV0dG9uO3JldHVybiBudWxsPT1hLnBhZ2VYJiZudWxsIT1iLmNsaWVudFgmJihjPWEudGFyZ2V0Lm93bmVyRG9jdW1lbnR8fGQsZT1jLmRvY3VtZW50RWxlbWVudCxmPWMuYm9keSxhLnBhZ2VYPWIuY2xpZW50WCsoZSYmZS5zY3JvbGxMZWZ0fHxmJiZmLnNjcm9sbExlZnR8fDApLShlJiZlLmNsaWVudExlZnR8fGYmJmYuY2xpZW50TGVmdHx8MCksYS5wYWdlWT1iLmNsaWVudFkrKGUmJmUuc2Nyb2xsVG9wfHxmJiZmLnNjcm9sbFRvcHx8MCktKGUmJmUuY2xpZW50VG9wfHxmJiZmLmNsaWVudFRvcHx8MCkpLGEud2hpY2h8fHZvaWQgMD09PWd8fChhLndoaWNoPTEmZz8xOjImZz8zOjQmZz8yOjApLGF9fSxmaXg6ZnVuY3Rpb24oYSl7aWYoYVtuLmV4cGFuZG9dKXJldHVybiBhO3ZhciBiLGMsZSxmPWEudHlwZSxnPWEsaD10aGlzLmZpeEhvb2tzW2ZdO2h8fCh0aGlzLmZpeEhvb2tzW2ZdPWg9ZWEudGVzdChmKT90aGlzLm1vdXNlSG9va3M6ZGEudGVzdChmKT90aGlzLmtleUhvb2tzOnt9KSxlPWgucHJvcHM/dGhpcy5wcm9wcy5jb25jYXQoaC5wcm9wcyk6dGhpcy5wcm9wcyxhPW5ldyBuLkV2ZW50KGcpLGI9ZS5sZW5ndGg7d2hpbGUoYi0tKWM9ZVtiXSxhW2NdPWdbY107cmV0dXJuIGEudGFyZ2V0fHwoYS50YXJnZXQ9ZCksMz09PWEudGFyZ2V0Lm5vZGVUeXBlJiYoYS50YXJnZXQ9YS50YXJnZXQucGFyZW50Tm9kZSksaC5maWx0ZXI/aC5maWx0ZXIoYSxnKTphfSxzcGVjaWFsOntsb2FkOntub0J1YmJsZTohMH0sZm9jdXM6e3RyaWdnZXI6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcyE9PWlhKCkmJnRoaXMuZm9jdXM/KHRoaXMuZm9jdXMoKSwhMSk6dm9pZCAwfSxkZWxlZ2F0ZVR5cGU6ImZvY3VzaW4ifSxibHVyOnt0cmlnZ2VyOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXM9PT1pYSgpJiZ0aGlzLmJsdXI/KHRoaXMuYmx1cigpLCExKTp2b2lkIDB9LGRlbGVnYXRlVHlwZToiZm9jdXNvdXQifSxjbGljazp7dHJpZ2dlcjpmdW5jdGlvbigpe3JldHVybiJjaGVja2JveCI9PT10aGlzLnR5cGUmJnRoaXMuY2xpY2smJm4ubm9kZU5hbWUodGhpcywiaW5wdXQiKT8odGhpcy5jbGljaygpLCExKTp2b2lkIDB9LF9kZWZhdWx0OmZ1bmN0aW9uKGEpe3JldHVybiBuLm5vZGVOYW1lKGEudGFyZ2V0LCJhIil9fSxiZWZvcmV1bmxvYWQ6e3Bvc3REaXNwYXRjaDpmdW5jdGlvbihhKXt2b2lkIDAhPT1hLnJlc3VsdCYmYS5vcmlnaW5hbEV2ZW50JiYoYS5vcmlnaW5hbEV2ZW50LnJldHVyblZhbHVlPWEucmVzdWx0KX19fX0sbi5yZW1vdmVFdmVudD1mdW5jdGlvbihhLGIsYyl7YS5yZW1vdmVFdmVudExpc3RlbmVyJiZhLnJlbW92ZUV2ZW50TGlzdGVuZXIoYixjKX0sbi5FdmVudD1mdW5jdGlvbihhLGIpe3JldHVybiB0aGlzIGluc3RhbmNlb2Ygbi5FdmVudD8oYSYmYS50eXBlPyh0aGlzLm9yaWdpbmFsRXZlbnQ9YSx0aGlzLnR5cGU9YS50eXBlLHRoaXMuaXNEZWZhdWx0UHJldmVudGVkPWEuZGVmYXVsdFByZXZlbnRlZHx8dm9pZCAwPT09YS5kZWZhdWx0UHJldmVudGVkJiZhLnJldHVyblZhbHVlPT09ITE/Z2E6aGEpOnRoaXMudHlwZT1hLGImJm4uZXh0ZW5kKHRoaXMsYiksdGhpcy50aW1lU3RhbXA9YSYmYS50aW1lU3RhbXB8fG4ubm93KCksdm9pZCh0aGlzW24uZXhwYW5kb109ITApKTpuZXcgbi5FdmVudChhLGIpfSxuLkV2ZW50LnByb3RvdHlwZT17Y29uc3RydWN0b3I6bi5FdmVudCxpc0RlZmF1bHRQcmV2ZW50ZWQ6aGEsaXNQcm9wYWdhdGlvblN0b3BwZWQ6aGEsaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ6aGEscHJldmVudERlZmF1bHQ6ZnVuY3Rpb24oKXt2YXIgYT10aGlzLm9yaWdpbmFsRXZlbnQ7dGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQ9Z2EsYSYmYS5wcmV2ZW50RGVmYXVsdCgpfSxzdG9wUHJvcGFnYXRpb246ZnVuY3Rpb24oKXt2YXIgYT10aGlzLm9yaWdpbmFsRXZlbnQ7dGhpcy5pc1Byb3BhZ2F0aW9uU3RvcHBlZD1nYSxhJiZhLnN0b3BQcm9wYWdhdGlvbigpfSxzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb246ZnVuY3Rpb24oKXt2YXIgYT10aGlzLm9yaWdpbmFsRXZlbnQ7dGhpcy5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZD1nYSxhJiZhLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpLHRoaXMuc3RvcFByb3BhZ2F0aW9uKCl9fSxuLmVhY2goe21vdXNlZW50ZXI6Im1vdXNlb3ZlciIsbW91c2VsZWF2ZToibW91c2VvdXQiLHBvaW50ZXJlbnRlcjoicG9pbnRlcm92ZXIiLHBvaW50ZXJsZWF2ZToicG9pbnRlcm91dCJ9LGZ1bmN0aW9uKGEsYil7bi5ldmVudC5zcGVjaWFsW2FdPXtkZWxlZ2F0ZVR5cGU6YixiaW5kVHlwZTpiLGhhbmRsZTpmdW5jdGlvbihhKXt2YXIgYyxkPXRoaXMsZT1hLnJlbGF0ZWRUYXJnZXQsZj1hLmhhbmRsZU9iajtyZXR1cm4gZSYmKGU9PT1kfHxuLmNvbnRhaW5zKGQsZSkpfHwoYS50eXBlPWYub3JpZ1R5cGUsYz1mLmhhbmRsZXIuYXBwbHkodGhpcyxhcmd1bWVudHMpLGEudHlwZT1iKSxjfX19KSxuLmZuLmV4dGVuZCh7b246ZnVuY3Rpb24oYSxiLGMsZCl7cmV0dXJuIGphKHRoaXMsYSxiLGMsZCl9LG9uZTpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gamEodGhpcyxhLGIsYyxkLDEpfSxvZmY6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkLGU7aWYoYSYmYS5wcmV2ZW50RGVmYXVsdCYmYS5oYW5kbGVPYmopcmV0dXJuIGQ9YS5oYW5kbGVPYmosbihhLmRlbGVnYXRlVGFyZ2V0KS5vZmYoZC5uYW1lc3BhY2U/ZC5vcmlnVHlwZSsiLiIrZC5uYW1lc3BhY2U6ZC5vcmlnVHlwZSxkLnNlbGVjdG9yLGQuaGFuZGxlciksdGhpcztpZigib2JqZWN0Ij09dHlwZW9mIGEpe2ZvcihlIGluIGEpdGhpcy5vZmYoZSxiLGFbZV0pO3JldHVybiB0aGlzfXJldHVybiBiIT09ITEmJiJmdW5jdGlvbiIhPXR5cGVvZiBifHwoYz1iLGI9dm9pZCAwKSxjPT09ITEmJihjPWhhKSx0aGlzLmVhY2goZnVuY3Rpb24oKXtuLmV2ZW50LnJlbW92ZSh0aGlzLGEsYyxiKX0pfX0pO3ZhciBrYT0vPCg/IWFyZWF8YnJ8Y29sfGVtYmVkfGhyfGltZ3xpbnB1dHxsaW5rfG1ldGF8cGFyYW0pKChbXHc6LV0rKVtePl0qKVwvPi9naSxsYT0vPHNjcmlwdHw8c3R5bGV8PGxpbmsvaSxtYT0vY2hlY2tlZFxzKig/OltePV18PVxzKi5jaGVja2VkLikvaSxuYT0vXnRydWVcLyguKikvLG9hPS9eXHMqPCEoPzpcW0NEQVRBXFt8LS0pfCg/OlxdXF18LS0pPlxzKiQvZztmdW5jdGlvbiBwYShhLGIpe3JldHVybiBuLm5vZGVOYW1lKGEsInRhYmxlIikmJm4ubm9kZU5hbWUoMTEhPT1iLm5vZGVUeXBlP2I6Yi5maXJzdENoaWxkLCJ0ciIpP2EuZ2V0RWxlbWVudHNCeVRhZ05hbWUoInRib2R5IilbMF18fGEuYXBwZW5kQ2hpbGQoYS5vd25lckRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInRib2R5IikpOmF9ZnVuY3Rpb24gcWEoYSl7cmV0dXJuIGEudHlwZT0obnVsbCE9PWEuZ2V0QXR0cmlidXRlKCJ0eXBlIikpKyIvIithLnR5cGUsYX1mdW5jdGlvbiByYShhKXt2YXIgYj1uYS5leGVjKGEudHlwZSk7cmV0dXJuIGI/YS50eXBlPWJbMV06YS5yZW1vdmVBdHRyaWJ1dGUoInR5cGUiKSxhfWZ1bmN0aW9uIHNhKGEsYil7dmFyIGMsZCxlLGYsZyxoLGksajtpZigxPT09Yi5ub2RlVHlwZSl7aWYoTi5oYXNEYXRhKGEpJiYoZj1OLmFjY2VzcyhhKSxnPU4uc2V0KGIsZiksaj1mLmV2ZW50cykpe2RlbGV0ZSBnLmhhbmRsZSxnLmV2ZW50cz17fTtmb3IoZSBpbiBqKWZvcihjPTAsZD1qW2VdLmxlbmd0aDtkPmM7YysrKW4uZXZlbnQuYWRkKGIsZSxqW2VdW2NdKX1PLmhhc0RhdGEoYSkmJihoPU8uYWNjZXNzKGEpLGk9bi5leHRlbmQoe30saCksTy5zZXQoYixpKSl9fWZ1bmN0aW9uIHRhKGEsYil7dmFyIGM9Yi5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpOyJpbnB1dCI9PT1jJiZYLnRlc3QoYS50eXBlKT9iLmNoZWNrZWQ9YS5jaGVja2VkOiJpbnB1dCIhPT1jJiYidGV4dGFyZWEiIT09Y3x8KGIuZGVmYXVsdFZhbHVlPWEuZGVmYXVsdFZhbHVlKX1mdW5jdGlvbiB1YShhLGIsYyxkKXtiPWYuYXBwbHkoW10sYik7dmFyIGUsZyxoLGksaixrLG09MCxvPWEubGVuZ3RoLHA9by0xLHE9YlswXSxyPW4uaXNGdW5jdGlvbihxKTtpZihyfHxvPjEmJiJzdHJpbmciPT10eXBlb2YgcSYmIWwuY2hlY2tDbG9uZSYmbWEudGVzdChxKSlyZXR1cm4gYS5lYWNoKGZ1bmN0aW9uKGUpe3ZhciBmPWEuZXEoZSk7ciYmKGJbMF09cS5jYWxsKHRoaXMsZSxmLmh0bWwoKSkpLHVhKGYsYixjLGQpfSk7aWYobyYmKGU9Y2EoYixhWzBdLm93bmVyRG9jdW1lbnQsITEsYSxkKSxnPWUuZmlyc3RDaGlsZCwxPT09ZS5jaGlsZE5vZGVzLmxlbmd0aCYmKGU9ZyksZ3x8ZCkpe2ZvcihoPW4ubWFwKF8oZSwic2NyaXB0IikscWEpLGk9aC5sZW5ndGg7bz5tO20rKylqPWUsbSE9PXAmJihqPW4uY2xvbmUoaiwhMCwhMCksaSYmbi5tZXJnZShoLF8oaiwic2NyaXB0IikpKSxjLmNhbGwoYVttXSxqLG0pO2lmKGkpZm9yKGs9aFtoLmxlbmd0aC0xXS5vd25lckRvY3VtZW50LG4ubWFwKGgscmEpLG09MDtpPm07bSsrKWo9aFttXSxaLnRlc3Qoai50eXBlfHwiIikmJiFOLmFjY2VzcyhqLCJnbG9iYWxFdmFsIikmJm4uY29udGFpbnMoayxqKSYmKGouc3JjP24uX2V2YWxVcmwmJm4uX2V2YWxVcmwoai5zcmMpOm4uZ2xvYmFsRXZhbChqLnRleHRDb250ZW50LnJlcGxhY2Uob2EsIiIpKSl9cmV0dXJuIGF9ZnVuY3Rpb24gdmEoYSxiLGMpe2Zvcih2YXIgZCxlPWI/bi5maWx0ZXIoYixhKTphLGY9MDtudWxsIT0oZD1lW2ZdKTtmKyspY3x8MSE9PWQubm9kZVR5cGV8fG4uY2xlYW5EYXRhKF8oZCkpLGQucGFyZW50Tm9kZSYmKGMmJm4uY29udGFpbnMoZC5vd25lckRvY3VtZW50LGQpJiZhYShfKGQsInNjcmlwdCIpKSxkLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZCkpO3JldHVybiBhfW4uZXh0ZW5kKHtodG1sUHJlZmlsdGVyOmZ1bmN0aW9uKGEpe3JldHVybiBhLnJlcGxhY2Uoa2EsIjwkMT48LyQyPiIpfSxjbG9uZTpmdW5jdGlvbihhLGIsYyl7dmFyIGQsZSxmLGcsaD1hLmNsb25lTm9kZSghMCksaT1uLmNvbnRhaW5zKGEub3duZXJEb2N1bWVudCxhKTtpZighKGwubm9DbG9uZUNoZWNrZWR8fDEhPT1hLm5vZGVUeXBlJiYxMSE9PWEubm9kZVR5cGV8fG4uaXNYTUxEb2MoYSkpKWZvcihnPV8oaCksZj1fKGEpLGQ9MCxlPWYubGVuZ3RoO2U+ZDtkKyspdGEoZltkXSxnW2RdKTtpZihiKWlmKGMpZm9yKGY9Znx8XyhhKSxnPWd8fF8oaCksZD0wLGU9Zi5sZW5ndGg7ZT5kO2QrKylzYShmW2RdLGdbZF0pO2Vsc2Ugc2EoYSxoKTtyZXR1cm4gZz1fKGgsInNjcmlwdCIpLGcubGVuZ3RoPjAmJmFhKGcsIWkmJl8oYSwic2NyaXB0IikpLGh9LGNsZWFuRGF0YTpmdW5jdGlvbihhKXtmb3IodmFyIGIsYyxkLGU9bi5ldmVudC5zcGVjaWFsLGY9MDt2b2lkIDAhPT0oYz1hW2ZdKTtmKyspaWYoTChjKSl7aWYoYj1jW04uZXhwYW5kb10pe2lmKGIuZXZlbnRzKWZvcihkIGluIGIuZXZlbnRzKWVbZF0/bi5ldmVudC5yZW1vdmUoYyxkKTpuLnJlbW92ZUV2ZW50KGMsZCxiLmhhbmRsZSk7Y1tOLmV4cGFuZG9dPXZvaWQgMH1jW08uZXhwYW5kb10mJihjW08uZXhwYW5kb109dm9pZCAwKX19fSksbi5mbi5leHRlbmQoe2RvbU1hbmlwOnVhLGRldGFjaDpmdW5jdGlvbihhKXtyZXR1cm4gdmEodGhpcyxhLCEwKX0scmVtb3ZlOmZ1bmN0aW9uKGEpe3JldHVybiB2YSh0aGlzLGEpfSx0ZXh0OmZ1bmN0aW9uKGEpe3JldHVybiBLKHRoaXMsZnVuY3Rpb24oYSl7cmV0dXJuIHZvaWQgMD09PWE/bi50ZXh0KHRoaXMpOnRoaXMuZW1wdHkoKS5lYWNoKGZ1bmN0aW9uKCl7MSE9PXRoaXMubm9kZVR5cGUmJjExIT09dGhpcy5ub2RlVHlwZSYmOSE9PXRoaXMubm9kZVR5cGV8fCh0aGlzLnRleHRDb250ZW50PWEpfSl9LG51bGwsYSxhcmd1bWVudHMubGVuZ3RoKX0sYXBwZW5kOmZ1bmN0aW9uKCl7cmV0dXJuIHVhKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKGEpe2lmKDE9PT10aGlzLm5vZGVUeXBlfHwxMT09PXRoaXMubm9kZVR5cGV8fDk9PT10aGlzLm5vZGVUeXBlKXt2YXIgYj1wYSh0aGlzLGEpO2IuYXBwZW5kQ2hpbGQoYSl9fSl9LHByZXBlbmQ6ZnVuY3Rpb24oKXtyZXR1cm4gdWEodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24oYSl7aWYoMT09PXRoaXMubm9kZVR5cGV8fDExPT09dGhpcy5ub2RlVHlwZXx8OT09PXRoaXMubm9kZVR5cGUpe3ZhciBiPXBhKHRoaXMsYSk7Yi5pbnNlcnRCZWZvcmUoYSxiLmZpcnN0Q2hpbGQpfX0pfSxiZWZvcmU6ZnVuY3Rpb24oKXtyZXR1cm4gdWEodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24oYSl7dGhpcy5wYXJlbnROb2RlJiZ0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGEsdGhpcyl9KX0sYWZ0ZXI6ZnVuY3Rpb24oKXtyZXR1cm4gdWEodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24oYSl7dGhpcy5wYXJlbnROb2RlJiZ0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGEsdGhpcy5uZXh0U2libGluZyl9KX0sZW1wdHk6ZnVuY3Rpb24oKXtmb3IodmFyIGEsYj0wO251bGwhPShhPXRoaXNbYl0pO2IrKykxPT09YS5ub2RlVHlwZSYmKG4uY2xlYW5EYXRhKF8oYSwhMSkpLGEudGV4dENvbnRlbnQ9IiIpO3JldHVybiB0aGlzfSxjbG9uZTpmdW5jdGlvbihhLGIpe3JldHVybiBhPW51bGw9PWE/ITE6YSxiPW51bGw9PWI/YTpiLHRoaXMubWFwKGZ1bmN0aW9uKCl7cmV0dXJuIG4uY2xvbmUodGhpcyxhLGIpfSl9LGh0bWw6ZnVuY3Rpb24oYSl7cmV0dXJuIEsodGhpcyxmdW5jdGlvbihhKXt2YXIgYj10aGlzWzBdfHx7fSxjPTAsZD10aGlzLmxlbmd0aDtpZih2b2lkIDA9PT1hJiYxPT09Yi5ub2RlVHlwZSlyZXR1cm4gYi5pbm5lckhUTUw7aWYoInN0cmluZyI9PXR5cGVvZiBhJiYhbGEudGVzdChhKSYmISRbKFkuZXhlYyhhKXx8WyIiLCIiXSlbMV0udG9Mb3dlckNhc2UoKV0pe2E9bi5odG1sUHJlZmlsdGVyKGEpO3RyeXtmb3IoO2Q+YztjKyspYj10aGlzW2NdfHx7fSwxPT09Yi5ub2RlVHlwZSYmKG4uY2xlYW5EYXRhKF8oYiwhMSkpLGIuaW5uZXJIVE1MPWEpO2I9MH1jYXRjaChlKXt9fWImJnRoaXMuZW1wdHkoKS5hcHBlbmQoYSl9LG51bGwsYSxhcmd1bWVudHMubGVuZ3RoKX0scmVwbGFjZVdpdGg6ZnVuY3Rpb24oKXt2YXIgYT1bXTtyZXR1cm4gdWEodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24oYil7dmFyIGM9dGhpcy5wYXJlbnROb2RlO24uaW5BcnJheSh0aGlzLGEpPDAmJihuLmNsZWFuRGF0YShfKHRoaXMpKSxjJiZjLnJlcGxhY2VDaGlsZChiLHRoaXMpKX0sYSl9fSksbi5lYWNoKHthcHBlbmRUbzoiYXBwZW5kIixwcmVwZW5kVG86InByZXBlbmQiLGluc2VydEJlZm9yZToiYmVmb3JlIixpbnNlcnRBZnRlcjoiYWZ0ZXIiLHJlcGxhY2VBbGw6InJlcGxhY2VXaXRoIn0sZnVuY3Rpb24oYSxiKXtuLmZuW2FdPWZ1bmN0aW9uKGEpe2Zvcih2YXIgYyxkPVtdLGU9bihhKSxmPWUubGVuZ3RoLTEsaD0wO2Y+PWg7aCsrKWM9aD09PWY/dGhpczp0aGlzLmNsb25lKCEwKSxuKGVbaF0pW2JdKGMpLGcuYXBwbHkoZCxjLmdldCgpKTtyZXR1cm4gdGhpcy5wdXNoU3RhY2soZCl9fSk7dmFyIHdhLHhhPXtIVE1MOiJibG9jayIsQk9EWToiYmxvY2sifTtmdW5jdGlvbiB5YShhLGIpe3ZhciBjPW4oYi5jcmVhdGVFbGVtZW50KGEpKS5hcHBlbmRUbyhiLmJvZHkpLGQ9bi5jc3MoY1swXSwiZGlzcGxheSIpO3JldHVybiBjLmRldGFjaCgpLGR9ZnVuY3Rpb24gemEoYSl7dmFyIGI9ZCxjPXhhW2FdO3JldHVybiBjfHwoYz15YShhLGIpLCJub25lIiE9PWMmJmN8fCh3YT0od2F8fG4oIjxpZnJhbWUgZnJhbWVib3JkZXI9JzAnIHdpZHRoPScwJyBoZWlnaHQ9JzAnLz4iKSkuYXBwZW5kVG8oYi5kb2N1bWVudEVsZW1lbnQpLGI9d2FbMF0uY29udGVudERvY3VtZW50LGIud3JpdGUoKSxiLmNsb3NlKCksYz15YShhLGIpLHdhLmRldGFjaCgpKSx4YVthXT1jKSxjfXZhciBBYT0vXm1hcmdpbi8sQmE9bmV3IFJlZ0V4cCgiXigiK1MrIikoPyFweClbYS16JV0rJCIsImkiKSxDYT1mdW5jdGlvbihiKXt2YXIgYz1iLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXc7cmV0dXJuIGMmJmMub3BlbmVyfHwoYz1hKSxjLmdldENvbXB1dGVkU3R5bGUoYil9LERhPWZ1bmN0aW9uKGEsYixjLGQpe3ZhciBlLGYsZz17fTtmb3IoZiBpbiBiKWdbZl09YS5zdHlsZVtmXSxhLnN0eWxlW2ZdPWJbZl07ZT1jLmFwcGx5KGEsZHx8W10pO2ZvcihmIGluIGIpYS5zdHlsZVtmXT1nW2ZdO3JldHVybiBlfSxFYT1kLmRvY3VtZW50RWxlbWVudDshZnVuY3Rpb24oKXt2YXIgYixjLGUsZixnPWQuY3JlYXRlRWxlbWVudCgiZGl2IiksaD1kLmNyZWF0ZUVsZW1lbnQoImRpdiIpO2lmKGguc3R5bGUpe2guc3R5bGUuYmFja2dyb3VuZENsaXA9ImNvbnRlbnQtYm94IixoLmNsb25lTm9kZSghMCkuc3R5bGUuYmFja2dyb3VuZENsaXA9IiIsbC5jbGVhckNsb25lU3R5bGU9ImNvbnRlbnQtYm94Ij09PWguc3R5bGUuYmFja2dyb3VuZENsaXAsZy5zdHlsZS5jc3NUZXh0PSJib3JkZXI6MDt3aWR0aDo4cHg7aGVpZ2h0OjA7dG9wOjA7bGVmdDotOTk5OXB4O3BhZGRpbmc6MDttYXJnaW4tdG9wOjFweDtwb3NpdGlvbjphYnNvbHV0ZSIsZy5hcHBlbmRDaGlsZChoKTtmdW5jdGlvbiBpKCl7aC5zdHlsZS5jc3NUZXh0PSItd2Via2l0LWJveC1zaXppbmc6Ym9yZGVyLWJveDstbW96LWJveC1zaXppbmc6Ym9yZGVyLWJveDtib3gtc2l6aW5nOmJvcmRlci1ib3g7cG9zaXRpb246cmVsYXRpdmU7ZGlzcGxheTpibG9jazttYXJnaW46YXV0bztib3JkZXI6MXB4O3BhZGRpbmc6MXB4O3RvcDoxJTt3aWR0aDo1MCUiLGguaW5uZXJIVE1MPSIiLEVhLmFwcGVuZENoaWxkKGcpO3ZhciBkPWEuZ2V0Q29tcHV0ZWRTdHlsZShoKTtiPSIxJSIhPT1kLnRvcCxmPSIycHgiPT09ZC5tYXJnaW5MZWZ0LGM9IjRweCI9PT1kLndpZHRoLGguc3R5bGUubWFyZ2luUmlnaHQ9IjUwJSIsZT0iNHB4Ij09PWQubWFyZ2luUmlnaHQsRWEucmVtb3ZlQ2hpbGQoZyl9bi5leHRlbmQobCx7cGl4ZWxQb3NpdGlvbjpmdW5jdGlvbigpe3JldHVybiBpKCksYn0sYm94U2l6aW5nUmVsaWFibGU6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbD09YyYmaSgpLGN9LHBpeGVsTWFyZ2luUmlnaHQ6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbD09YyYmaSgpLGV9LHJlbGlhYmxlTWFyZ2luTGVmdDpmdW5jdGlvbigpe3JldHVybiBudWxsPT1jJiZpKCksZn0scmVsaWFibGVNYXJnaW5SaWdodDpmdW5jdGlvbigpe3ZhciBiLGM9aC5hcHBlbmRDaGlsZChkLmNyZWF0ZUVsZW1lbnQoImRpdiIpKTtyZXR1cm4gYy5zdHlsZS5jc3NUZXh0PWguc3R5bGUuY3NzVGV4dD0iLXdlYmtpdC1ib3gtc2l6aW5nOmNvbnRlbnQtYm94O2JveC1zaXppbmc6Y29udGVudC1ib3g7ZGlzcGxheTpibG9jazttYXJnaW46MDtib3JkZXI6MDtwYWRkaW5nOjAiLGMuc3R5bGUubWFyZ2luUmlnaHQ9Yy5zdHlsZS53aWR0aD0iMCIsaC5zdHlsZS53aWR0aD0iMXB4IixFYS5hcHBlbmRDaGlsZChnKSxiPSFwYXJzZUZsb2F0KGEuZ2V0Q29tcHV0ZWRTdHlsZShjKS5tYXJnaW5SaWdodCksRWEucmVtb3ZlQ2hpbGQoZyksaC5yZW1vdmVDaGlsZChjKSxifX0pfX0oKTtmdW5jdGlvbiBGYShhLGIsYyl7dmFyIGQsZSxmLGcsaD1hLnN0eWxlO3JldHVybiBjPWN8fENhKGEpLGc9Yz9jLmdldFByb3BlcnR5VmFsdWUoYil8fGNbYl06dm9pZCAwLCIiIT09ZyYmdm9pZCAwIT09Z3x8bi5jb250YWlucyhhLm93bmVyRG9jdW1lbnQsYSl8fChnPW4uc3R5bGUoYSxiKSksYyYmIWwucGl4ZWxNYXJnaW5SaWdodCgpJiZCYS50ZXN0KGcpJiZBYS50ZXN0KGIpJiYoZD1oLndpZHRoLGU9aC5taW5XaWR0aCxmPWgubWF4V2lkdGgsaC5taW5XaWR0aD1oLm1heFdpZHRoPWgud2lkdGg9ZyxnPWMud2lkdGgsaC53aWR0aD1kLGgubWluV2lkdGg9ZSxoLm1heFdpZHRoPWYpLHZvaWQgMCE9PWc/ZysiIjpnfWZ1bmN0aW9uIEdhKGEsYil7cmV0dXJue2dldDpmdW5jdGlvbigpe3JldHVybiBhKCk/dm9pZCBkZWxldGUgdGhpcy5nZXQ6KHRoaXMuZ2V0PWIpLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19fXZhciBIYT0vXihub25lfHRhYmxlKD8hLWNbZWFdKS4rKS8sSWE9e3Bvc2l0aW9uOiJhYnNvbHV0ZSIsdmlzaWJpbGl0eToiaGlkZGVuIixkaXNwbGF5OiJibG9jayJ9LEphPXtsZXR0ZXJTcGFjaW5nOiIwIixmb250V2VpZ2h0OiI0MDAifSxLYT1bIldlYmtpdCIsIk8iLCJNb3oiLCJtcyJdLExhPWQuY3JlYXRlRWxlbWVudCgiZGl2Iikuc3R5bGU7ZnVuY3Rpb24gTWEoYSl7aWYoYSBpbiBMYSlyZXR1cm4gYTt2YXIgYj1hWzBdLnRvVXBwZXJDYXNlKCkrYS5zbGljZSgxKSxjPUthLmxlbmd0aDt3aGlsZShjLS0paWYoYT1LYVtjXStiLGEgaW4gTGEpcmV0dXJuIGF9ZnVuY3Rpb24gTmEoYSxiLGMpe3ZhciBkPVQuZXhlYyhiKTtyZXR1cm4gZD9NYXRoLm1heCgwLGRbMl0tKGN8fDApKSsoZFszXXx8InB4Iik6Yn1mdW5jdGlvbiBPYShhLGIsYyxkLGUpe2Zvcih2YXIgZj1jPT09KGQ/ImJvcmRlciI6ImNvbnRlbnQiKT80OiJ3aWR0aCI9PT1iPzE6MCxnPTA7ND5mO2YrPTIpIm1hcmdpbiI9PT1jJiYoZys9bi5jc3MoYSxjK1VbZl0sITAsZSkpLGQ/KCJjb250ZW50Ij09PWMmJihnLT1uLmNzcyhhLCJwYWRkaW5nIitVW2ZdLCEwLGUpKSwibWFyZ2luIiE9PWMmJihnLT1uLmNzcyhhLCJib3JkZXIiK1VbZl0rIldpZHRoIiwhMCxlKSkpOihnKz1uLmNzcyhhLCJwYWRkaW5nIitVW2ZdLCEwLGUpLCJwYWRkaW5nIiE9PWMmJihnKz1uLmNzcyhhLCJib3JkZXIiK1VbZl0rIldpZHRoIiwhMCxlKSkpO3JldHVybiBnfWZ1bmN0aW9uIFBhKGIsYyxlKXt2YXIgZj0hMCxnPSJ3aWR0aCI9PT1jP2Iub2Zmc2V0V2lkdGg6Yi5vZmZzZXRIZWlnaHQsaD1DYShiKSxpPSJib3JkZXItYm94Ij09PW4uY3NzKGIsImJveFNpemluZyIsITEsaCk7aWYoZC5tc0Z1bGxzY3JlZW5FbGVtZW50JiZhLnRvcCE9PWEmJmIuZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGgmJihnPU1hdGgucm91bmQoMTAwKmIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KClbY10pKSwwPj1nfHxudWxsPT1nKXtpZihnPUZhKGIsYyxoKSwoMD5nfHxudWxsPT1nKSYmKGc9Yi5zdHlsZVtjXSksQmEudGVzdChnKSlyZXR1cm4gZztmPWkmJihsLmJveFNpemluZ1JlbGlhYmxlKCl8fGc9PT1iLnN0eWxlW2NdKSxnPXBhcnNlRmxvYXQoZyl8fDB9cmV0dXJuIGcrT2EoYixjLGV8fChpPyJib3JkZXIiOiJjb250ZW50IiksZixoKSsicHgifWZ1bmN0aW9uIFFhKGEsYil7Zm9yKHZhciBjLGQsZSxmPVtdLGc9MCxoPWEubGVuZ3RoO2g+ZztnKyspZD1hW2ddLGQuc3R5bGUmJihmW2ddPU4uZ2V0KGQsIm9sZGRpc3BsYXkiKSxjPWQuc3R5bGUuZGlzcGxheSxiPyhmW2ddfHwibm9uZSIhPT1jfHwoZC5zdHlsZS5kaXNwbGF5PSIiKSwiIj09PWQuc3R5bGUuZGlzcGxheSYmVihkKSYmKGZbZ109Ti5hY2Nlc3MoZCwib2xkZGlzcGxheSIsemEoZC5ub2RlTmFtZSkpKSk6KGU9VihkKSwibm9uZSI9PT1jJiZlfHxOLnNldChkLCJvbGRkaXNwbGF5IixlP2M6bi5jc3MoZCwiZGlzcGxheSIpKSkpO2ZvcihnPTA7aD5nO2crKylkPWFbZ10sZC5zdHlsZSYmKGImJiJub25lIiE9PWQuc3R5bGUuZGlzcGxheSYmIiIhPT1kLnN0eWxlLmRpc3BsYXl8fChkLnN0eWxlLmRpc3BsYXk9Yj9mW2ddfHwiIjoibm9uZSIpKTtyZXR1cm4gYX1uLmV4dGVuZCh7Y3NzSG9va3M6e29wYWNpdHk6e2dldDpmdW5jdGlvbihhLGIpe2lmKGIpe3ZhciBjPUZhKGEsIm9wYWNpdHkiKTtyZXR1cm4iIj09PWM/IjEiOmN9fX19LGNzc051bWJlcjp7YW5pbWF0aW9uSXRlcmF0aW9uQ291bnQ6ITAsY29sdW1uQ291bnQ6ITAsZmlsbE9wYWNpdHk6ITAsZmxleEdyb3c6ITAsZmxleFNocmluazohMCxmb250V2VpZ2h0OiEwLGxpbmVIZWlnaHQ6ITAsb3BhY2l0eTohMCxvcmRlcjohMCxvcnBoYW5zOiEwLHdpZG93czohMCx6SW5kZXg6ITAsem9vbTohMH0sY3NzUHJvcHM6eyJmbG9hdCI6ImNzc0Zsb2F0In0sc3R5bGU6ZnVuY3Rpb24oYSxiLGMsZCl7aWYoYSYmMyE9PWEubm9kZVR5cGUmJjghPT1hLm5vZGVUeXBlJiZhLnN0eWxlKXt2YXIgZSxmLGcsaD1uLmNhbWVsQ2FzZShiKSxpPWEuc3R5bGU7cmV0dXJuIGI9bi5jc3NQcm9wc1toXXx8KG4uY3NzUHJvcHNbaF09TWEoaCl8fGgpLGc9bi5jc3NIb29rc1tiXXx8bi5jc3NIb29rc1toXSx2b2lkIDA9PT1jP2cmJiJnZXQiaW4gZyYmdm9pZCAwIT09KGU9Zy5nZXQoYSwhMSxkKSk/ZTppW2JdOihmPXR5cGVvZiBjLCJzdHJpbmciPT09ZiYmKGU9VC5leGVjKGMpKSYmZVsxXSYmKGM9VyhhLGIsZSksZj0ibnVtYmVyIiksbnVsbCE9YyYmYz09PWMmJigibnVtYmVyIj09PWYmJihjKz1lJiZlWzNdfHwobi5jc3NOdW1iZXJbaF0/IiI6InB4IikpLGwuY2xlYXJDbG9uZVN0eWxlfHwiIiE9PWN8fDAhPT1iLmluZGV4T2YoImJhY2tncm91bmQiKXx8KGlbYl09ImluaGVyaXQiKSxnJiYic2V0ImluIGcmJnZvaWQgMD09PShjPWcuc2V0KGEsYyxkKSl8fChpW2JdPWMpKSx2b2lkIDApfX0sY3NzOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciBlLGYsZyxoPW4uY2FtZWxDYXNlKGIpO3JldHVybiBiPW4uY3NzUHJvcHNbaF18fChuLmNzc1Byb3BzW2hdPU1hKGgpfHxoKSxnPW4uY3NzSG9va3NbYl18fG4uY3NzSG9va3NbaF0sZyYmImdldCJpbiBnJiYoZT1nLmdldChhLCEwLGMpKSx2b2lkIDA9PT1lJiYoZT1GYShhLGIsZCkpLCJub3JtYWwiPT09ZSYmYiBpbiBKYSYmKGU9SmFbYl0pLCIiPT09Y3x8Yz8oZj1wYXJzZUZsb2F0KGUpLGM9PT0hMHx8aXNGaW5pdGUoZik/Znx8MDplKTplfX0pLG4uZWFjaChbImhlaWdodCIsIndpZHRoIl0sZnVuY3Rpb24oYSxiKXtuLmNzc0hvb2tzW2JdPXtnZXQ6ZnVuY3Rpb24oYSxjLGQpe3JldHVybiBjP0hhLnRlc3Qobi5jc3MoYSwiZGlzcGxheSIpKSYmMD09PWEub2Zmc2V0V2lkdGg/RGEoYSxJYSxmdW5jdGlvbigpe3JldHVybiBQYShhLGIsZCl9KTpQYShhLGIsZCk6dm9pZCAwfSxzZXQ6ZnVuY3Rpb24oYSxjLGQpe3ZhciBlLGY9ZCYmQ2EoYSksZz1kJiZPYShhLGIsZCwiYm9yZGVyLWJveCI9PT1uLmNzcyhhLCJib3hTaXppbmciLCExLGYpLGYpO3JldHVybiBnJiYoZT1ULmV4ZWMoYykpJiYicHgiIT09KGVbM118fCJweCIpJiYoYS5zdHlsZVtiXT1jLGM9bi5jc3MoYSxiKSksTmEoYSxjLGcpfX19KSxuLmNzc0hvb2tzLm1hcmdpbkxlZnQ9R2EobC5yZWxpYWJsZU1hcmdpbkxlZnQsZnVuY3Rpb24oYSxiKXtyZXR1cm4gYj8ocGFyc2VGbG9hdChGYShhLCJtYXJnaW5MZWZ0IikpfHxhLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQtRGEoYSx7bWFyZ2luTGVmdDowfSxmdW5jdGlvbigpe3JldHVybiBhLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnR9KSkrInB4Ijp2b2lkIDB9KSxuLmNzc0hvb2tzLm1hcmdpblJpZ2h0PUdhKGwucmVsaWFibGVNYXJnaW5SaWdodCxmdW5jdGlvbihhLGIpe3JldHVybiBiP0RhKGEse2Rpc3BsYXk6ImlubGluZS1ibG9jayJ9LEZhLFthLCJtYXJnaW5SaWdodCJdKTp2b2lkIDB9KSxuLmVhY2goe21hcmdpbjoiIixwYWRkaW5nOiIiLGJvcmRlcjoiV2lkdGgifSxmdW5jdGlvbihhLGIpe24uY3NzSG9va3NbYStiXT17ZXhwYW5kOmZ1bmN0aW9uKGMpe2Zvcih2YXIgZD0wLGU9e30sZj0ic3RyaW5nIj09dHlwZW9mIGM/Yy5zcGxpdCgiICIpOltjXTs0PmQ7ZCsrKWVbYStVW2RdK2JdPWZbZF18fGZbZC0yXXx8ZlswXTtyZXR1cm4gZX19LEFhLnRlc3QoYSl8fChuLmNzc0hvb2tzW2ErYl0uc2V0PU5hKX0pLG4uZm4uZXh0ZW5kKHtjc3M6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gSyh0aGlzLGZ1bmN0aW9uKGEsYixjKXt2YXIgZCxlLGY9e30sZz0wO2lmKG4uaXNBcnJheShiKSl7Zm9yKGQ9Q2EoYSksZT1iLmxlbmd0aDtlPmc7ZysrKWZbYltnXV09bi5jc3MoYSxiW2ddLCExLGQpO3JldHVybiBmfXJldHVybiB2b2lkIDAhPT1jP24uc3R5bGUoYSxiLGMpOm4uY3NzKGEsYil9LGEsYixhcmd1bWVudHMubGVuZ3RoPjEpfSxzaG93OmZ1bmN0aW9uKCl7cmV0dXJuIFFhKHRoaXMsITApfSxoaWRlOmZ1bmN0aW9uKCl7cmV0dXJuIFFhKHRoaXMpfSx0b2dnbGU6ZnVuY3Rpb24oYSl7cmV0dXJuImJvb2xlYW4iPT10eXBlb2YgYT9hP3RoaXMuc2hvdygpOnRoaXMuaGlkZSgpOnRoaXMuZWFjaChmdW5jdGlvbigpe1YodGhpcyk/bih0aGlzKS5zaG93KCk6bih0aGlzKS5oaWRlKCl9KX19KTtmdW5jdGlvbiBSYShhLGIsYyxkLGUpe3JldHVybiBuZXcgUmEucHJvdG90eXBlLmluaXQoYSxiLGMsZCxlKX1uLlR3ZWVuPVJhLFJhLnByb3RvdHlwZT17Y29uc3RydWN0b3I6UmEsaW5pdDpmdW5jdGlvbihhLGIsYyxkLGUsZil7dGhpcy5lbGVtPWEsdGhpcy5wcm9wPWMsdGhpcy5lYXNpbmc9ZXx8bi5lYXNpbmcuX2RlZmF1bHQsdGhpcy5vcHRpb25zPWIsdGhpcy5zdGFydD10aGlzLm5vdz10aGlzLmN1cigpLHRoaXMuZW5kPWQsdGhpcy51bml0PWZ8fChuLmNzc051bWJlcltjXT8iIjoicHgiKX0sY3VyOmZ1bmN0aW9uKCl7dmFyIGE9UmEucHJvcEhvb2tzW3RoaXMucHJvcF07cmV0dXJuIGEmJmEuZ2V0P2EuZ2V0KHRoaXMpOlJhLnByb3BIb29rcy5fZGVmYXVsdC5nZXQodGhpcyl9LHJ1bjpmdW5jdGlvbihhKXt2YXIgYixjPVJhLnByb3BIb29rc1t0aGlzLnByb3BdO3JldHVybiB0aGlzLm9wdGlvbnMuZHVyYXRpb24/dGhpcy5wb3M9Yj1uLmVhc2luZ1t0aGlzLmVhc2luZ10oYSx0aGlzLm9wdGlvbnMuZHVyYXRpb24qYSwwLDEsdGhpcy5vcHRpb25zLmR1cmF0aW9uKTp0aGlzLnBvcz1iPWEsdGhpcy5ub3c9KHRoaXMuZW5kLXRoaXMuc3RhcnQpKmIrdGhpcy5zdGFydCx0aGlzLm9wdGlvbnMuc3RlcCYmdGhpcy5vcHRpb25zLnN0ZXAuY2FsbCh0aGlzLmVsZW0sdGhpcy5ub3csdGhpcyksYyYmYy5zZXQ/Yy5zZXQodGhpcyk6UmEucHJvcEhvb2tzLl9kZWZhdWx0LnNldCh0aGlzKSx0aGlzfX0sUmEucHJvdG90eXBlLmluaXQucHJvdG90eXBlPVJhLnByb3RvdHlwZSxSYS5wcm9wSG9va3M9e19kZWZhdWx0OntnZXQ6ZnVuY3Rpb24oYSl7dmFyIGI7cmV0dXJuIDEhPT1hLmVsZW0ubm9kZVR5cGV8fG51bGwhPWEuZWxlbVthLnByb3BdJiZudWxsPT1hLmVsZW0uc3R5bGVbYS5wcm9wXT9hLmVsZW1bYS5wcm9wXTooYj1uLmNzcyhhLmVsZW0sYS5wcm9wLCIiKSxiJiYiYXV0byIhPT1iP2I6MCl9LHNldDpmdW5jdGlvbihhKXtuLmZ4LnN0ZXBbYS5wcm9wXT9uLmZ4LnN0ZXBbYS5wcm9wXShhKToxIT09YS5lbGVtLm5vZGVUeXBlfHxudWxsPT1hLmVsZW0uc3R5bGVbbi5jc3NQcm9wc1thLnByb3BdXSYmIW4uY3NzSG9va3NbYS5wcm9wXT9hLmVsZW1bYS5wcm9wXT1hLm5vdzpuLnN0eWxlKGEuZWxlbSxhLnByb3AsYS5ub3crYS51bml0KX19fSxSYS5wcm9wSG9va3Muc2Nyb2xsVG9wPVJhLnByb3BIb29rcy5zY3JvbGxMZWZ0PXtzZXQ6ZnVuY3Rpb24oYSl7YS5lbGVtLm5vZGVUeXBlJiZhLmVsZW0ucGFyZW50Tm9kZSYmKGEuZWxlbVthLnByb3BdPWEubm93KX19LG4uZWFzaW5nPXtsaW5lYXI6ZnVuY3Rpb24oYSl7cmV0dXJuIGF9LHN3aW5nOmZ1bmN0aW9uKGEpe3JldHVybi41LU1hdGguY29zKGEqTWF0aC5QSSkvMn0sX2RlZmF1bHQ6InN3aW5nIn0sbi5meD1SYS5wcm90b3R5cGUuaW5pdCxuLmZ4LnN0ZXA9e307dmFyIFNhLFRhLFVhPS9eKD86dG9nZ2xlfHNob3d8aGlkZSkkLyxWYT0vcXVldWVIb29rcyQvO2Z1bmN0aW9uIFdhKCl7cmV0dXJuIGEuc2V0VGltZW91dChmdW5jdGlvbigpe1NhPXZvaWQgMH0pLFNhPW4ubm93KCl9ZnVuY3Rpb24gWGEoYSxiKXt2YXIgYyxkPTAsZT17aGVpZ2h0OmF9O2ZvcihiPWI/MTowOzQ+ZDtkKz0yLWIpYz1VW2RdLGVbIm1hcmdpbiIrY109ZVsicGFkZGluZyIrY109YTtyZXR1cm4gYiYmKGUub3BhY2l0eT1lLndpZHRoPWEpLGV9ZnVuY3Rpb24gWWEoYSxiLGMpe2Zvcih2YXIgZCxlPShfYS50d2VlbmVyc1tiXXx8W10pLmNvbmNhdChfYS50d2VlbmVyc1siKiJdKSxmPTAsZz1lLmxlbmd0aDtnPmY7ZisrKWlmKGQ9ZVtmXS5jYWxsKGMsYixhKSlyZXR1cm4gZH1mdW5jdGlvbiBaYShhLGIsYyl7dmFyIGQsZSxmLGcsaCxpLGosayxsPXRoaXMsbT17fSxvPWEuc3R5bGUscD1hLm5vZGVUeXBlJiZWKGEpLHE9Ti5nZXQoYSwiZnhzaG93Iik7Yy5xdWV1ZXx8KGg9bi5fcXVldWVIb29rcyhhLCJmeCIpLG51bGw9PWgudW5xdWV1ZWQmJihoLnVucXVldWVkPTAsaT1oLmVtcHR5LmZpcmUsaC5lbXB0eS5maXJlPWZ1bmN0aW9uKCl7aC51bnF1ZXVlZHx8aSgpfSksaC51bnF1ZXVlZCsrLGwuYWx3YXlzKGZ1bmN0aW9uKCl7bC5hbHdheXMoZnVuY3Rpb24oKXtoLnVucXVldWVkLS0sbi5xdWV1ZShhLCJmeCIpLmxlbmd0aHx8aC5lbXB0eS5maXJlKCl9KX0pKSwxPT09YS5ub2RlVHlwZSYmKCJoZWlnaHQiaW4gYnx8IndpZHRoImluIGIpJiYoYy5vdmVyZmxvdz1bby5vdmVyZmxvdyxvLm92ZXJmbG93WCxvLm92ZXJmbG93WV0saj1uLmNzcyhhLCJkaXNwbGF5Iiksaz0ibm9uZSI9PT1qP04uZ2V0KGEsIm9sZGRpc3BsYXkiKXx8emEoYS5ub2RlTmFtZSk6aiwiaW5saW5lIj09PWsmJiJub25lIj09PW4uY3NzKGEsImZsb2F0IikmJihvLmRpc3BsYXk9ImlubGluZS1ibG9jayIpKSxjLm92ZXJmbG93JiYoby5vdmVyZmxvdz0iaGlkZGVuIixsLmFsd2F5cyhmdW5jdGlvbigpe28ub3ZlcmZsb3c9Yy5vdmVyZmxvd1swXSxvLm92ZXJmbG93WD1jLm92ZXJmbG93WzFdLG8ub3ZlcmZsb3dZPWMub3ZlcmZsb3dbMl19KSk7Zm9yKGQgaW4gYilpZihlPWJbZF0sVWEuZXhlYyhlKSl7aWYoZGVsZXRlIGJbZF0sZj1mfHwidG9nZ2xlIj09PWUsZT09PShwPyJoaWRlIjoic2hvdyIpKXtpZigic2hvdyIhPT1lfHwhcXx8dm9pZCAwPT09cVtkXSljb250aW51ZTtwPSEwfW1bZF09cSYmcVtkXXx8bi5zdHlsZShhLGQpfWVsc2Ugaj12b2lkIDA7aWYobi5pc0VtcHR5T2JqZWN0KG0pKSJpbmxpbmUiPT09KCJub25lIj09PWo/emEoYS5ub2RlTmFtZSk6aikmJihvLmRpc3BsYXk9aik7ZWxzZXtxPyJoaWRkZW4iaW4gcSYmKHA9cS5oaWRkZW4pOnE9Ti5hY2Nlc3MoYSwiZnhzaG93Iix7fSksZiYmKHEuaGlkZGVuPSFwKSxwP24oYSkuc2hvdygpOmwuZG9uZShmdW5jdGlvbigpe24oYSkuaGlkZSgpfSksbC5kb25lKGZ1bmN0aW9uKCl7dmFyIGI7Ti5yZW1vdmUoYSwiZnhzaG93Iik7Zm9yKGIgaW4gbSluLnN0eWxlKGEsYixtW2JdKX0pO2ZvcihkIGluIG0pZz1ZYShwP3FbZF06MCxkLGwpLGQgaW4gcXx8KHFbZF09Zy5zdGFydCxwJiYoZy5lbmQ9Zy5zdGFydCxnLnN0YXJ0PSJ3aWR0aCI9PT1kfHwiaGVpZ2h0Ij09PWQ/MTowKSl9fWZ1bmN0aW9uICRhKGEsYil7dmFyIGMsZCxlLGYsZztmb3IoYyBpbiBhKWlmKGQ9bi5jYW1lbENhc2UoYyksZT1iW2RdLGY9YVtjXSxuLmlzQXJyYXkoZikmJihlPWZbMV0sZj1hW2NdPWZbMF0pLGMhPT1kJiYoYVtkXT1mLGRlbGV0ZSBhW2NdKSxnPW4uY3NzSG9va3NbZF0sZyYmImV4cGFuZCJpbiBnKXtmPWcuZXhwYW5kKGYpLGRlbGV0ZSBhW2RdO2ZvcihjIGluIGYpYyBpbiBhfHwoYVtjXT1mW2NdLGJbY109ZSl9ZWxzZSBiW2RdPWV9ZnVuY3Rpb24gX2EoYSxiLGMpe3ZhciBkLGUsZj0wLGc9X2EucHJlZmlsdGVycy5sZW5ndGgsaD1uLkRlZmVycmVkKCkuYWx3YXlzKGZ1bmN0aW9uKCl7ZGVsZXRlIGkuZWxlbX0pLGk9ZnVuY3Rpb24oKXtpZihlKXJldHVybiExO2Zvcih2YXIgYj1TYXx8V2EoKSxjPU1hdGgubWF4KDAsai5zdGFydFRpbWUrai5kdXJhdGlvbi1iKSxkPWMvai5kdXJhdGlvbnx8MCxmPTEtZCxnPTAsaT1qLnR3ZWVucy5sZW5ndGg7aT5nO2crKylqLnR3ZWVuc1tnXS5ydW4oZik7cmV0dXJuIGgubm90aWZ5V2l0aChhLFtqLGYsY10pLDE+ZiYmaT9jOihoLnJlc29sdmVXaXRoKGEsW2pdKSwhMSl9LGo9aC5wcm9taXNlKHtlbGVtOmEscHJvcHM6bi5leHRlbmQoe30sYiksb3B0czpuLmV4dGVuZCghMCx7c3BlY2lhbEVhc2luZzp7fSxlYXNpbmc6bi5lYXNpbmcuX2RlZmF1bHR9LGMpLG9yaWdpbmFsUHJvcGVydGllczpiLG9yaWdpbmFsT3B0aW9uczpjLHN0YXJ0VGltZTpTYXx8V2EoKSxkdXJhdGlvbjpjLmR1cmF0aW9uLHR3ZWVuczpbXSxjcmVhdGVUd2VlbjpmdW5jdGlvbihiLGMpe3ZhciBkPW4uVHdlZW4oYSxqLm9wdHMsYixjLGoub3B0cy5zcGVjaWFsRWFzaW5nW2JdfHxqLm9wdHMuZWFzaW5nKTtyZXR1cm4gai50d2VlbnMucHVzaChkKSxkfSxzdG9wOmZ1bmN0aW9uKGIpe3ZhciBjPTAsZD1iP2oudHdlZW5zLmxlbmd0aDowO2lmKGUpcmV0dXJuIHRoaXM7Zm9yKGU9ITA7ZD5jO2MrKylqLnR3ZWVuc1tjXS5ydW4oMSk7cmV0dXJuIGI/KGgubm90aWZ5V2l0aChhLFtqLDEsMF0pLGgucmVzb2x2ZVdpdGgoYSxbaixiXSkpOmgucmVqZWN0V2l0aChhLFtqLGJdKSx0aGlzfX0pLGs9ai5wcm9wcztmb3IoJGEoayxqLm9wdHMuc3BlY2lhbEVhc2luZyk7Zz5mO2YrKylpZihkPV9hLnByZWZpbHRlcnNbZl0uY2FsbChqLGEsayxqLm9wdHMpKXJldHVybiBuLmlzRnVuY3Rpb24oZC5zdG9wKSYmKG4uX3F1ZXVlSG9va3Moai5lbGVtLGoub3B0cy5xdWV1ZSkuc3RvcD1uLnByb3h5KGQuc3RvcCxkKSksZDtyZXR1cm4gbi5tYXAoayxZYSxqKSxuLmlzRnVuY3Rpb24oai5vcHRzLnN0YXJ0KSYmai5vcHRzLnN0YXJ0LmNhbGwoYSxqKSxuLmZ4LnRpbWVyKG4uZXh0ZW5kKGkse2VsZW06YSxhbmltOmoscXVldWU6ai5vcHRzLnF1ZXVlfSkpLGoucHJvZ3Jlc3Moai5vcHRzLnByb2dyZXNzKS5kb25lKGoub3B0cy5kb25lLGoub3B0cy5jb21wbGV0ZSkuZmFpbChqLm9wdHMuZmFpbCkuYWx3YXlzKGoub3B0cy5hbHdheXMpfW4uQW5pbWF0aW9uPW4uZXh0ZW5kKF9hLHt0d2VlbmVyczp7IioiOltmdW5jdGlvbihhLGIpe3ZhciBjPXRoaXMuY3JlYXRlVHdlZW4oYSxiKTtyZXR1cm4gVyhjLmVsZW0sYSxULmV4ZWMoYiksYyksY31dfSx0d2VlbmVyOmZ1bmN0aW9uKGEsYil7bi5pc0Z1bmN0aW9uKGEpPyhiPWEsYT1bIioiXSk6YT1hLm1hdGNoKEcpO2Zvcih2YXIgYyxkPTAsZT1hLmxlbmd0aDtlPmQ7ZCsrKWM9YVtkXSxfYS50d2VlbmVyc1tjXT1fYS50d2VlbmVyc1tjXXx8W10sX2EudHdlZW5lcnNbY10udW5zaGlmdChiKX0scHJlZmlsdGVyczpbWmFdLHByZWZpbHRlcjpmdW5jdGlvbihhLGIpe2I/X2EucHJlZmlsdGVycy51bnNoaWZ0KGEpOl9hLnByZWZpbHRlcnMucHVzaChhKX19KSxuLnNwZWVkPWZ1bmN0aW9uKGEsYixjKXt2YXIgZD1hJiYib2JqZWN0Ij09dHlwZW9mIGE/bi5leHRlbmQoe30sYSk6e2NvbXBsZXRlOmN8fCFjJiZifHxuLmlzRnVuY3Rpb24oYSkmJmEsZHVyYXRpb246YSxlYXNpbmc6YyYmYnx8YiYmIW4uaXNGdW5jdGlvbihiKSYmYn07cmV0dXJuIGQuZHVyYXRpb249bi5meC5vZmY/MDoibnVtYmVyIj09dHlwZW9mIGQuZHVyYXRpb24/ZC5kdXJhdGlvbjpkLmR1cmF0aW9uIGluIG4uZnguc3BlZWRzP24uZnguc3BlZWRzW2QuZHVyYXRpb25dOm4uZnguc3BlZWRzLl9kZWZhdWx0LG51bGwhPWQucXVldWUmJmQucXVldWUhPT0hMHx8KGQucXVldWU9ImZ4IiksZC5vbGQ9ZC5jb21wbGV0ZSxkLmNvbXBsZXRlPWZ1bmN0aW9uKCl7bi5pc0Z1bmN0aW9uKGQub2xkKSYmZC5vbGQuY2FsbCh0aGlzKSxkLnF1ZXVlJiZuLmRlcXVldWUodGhpcyxkLnF1ZXVlKX0sZH0sbi5mbi5leHRlbmQoe2ZhZGVUbzpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gdGhpcy5maWx0ZXIoVikuY3NzKCJvcGFjaXR5IiwwKS5zaG93KCkuZW5kKCkuYW5pbWF0ZSh7b3BhY2l0eTpifSxhLGMsZCl9LGFuaW1hdGU6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGU9bi5pc0VtcHR5T2JqZWN0KGEpLGY9bi5zcGVlZChiLGMsZCksZz1mdW5jdGlvbigpe3ZhciBiPV9hKHRoaXMsbi5leHRlbmQoe30sYSksZik7KGV8fE4uZ2V0KHRoaXMsImZpbmlzaCIpKSYmYi5zdG9wKCEwKX07cmV0dXJuIGcuZmluaXNoPWcsZXx8Zi5xdWV1ZT09PSExP3RoaXMuZWFjaChnKTp0aGlzLnF1ZXVlKGYucXVldWUsZyl9LHN0b3A6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkPWZ1bmN0aW9uKGEpe3ZhciBiPWEuc3RvcDtkZWxldGUgYS5zdG9wLGIoYyl9O3JldHVybiJzdHJpbmciIT10eXBlb2YgYSYmKGM9YixiPWEsYT12b2lkIDApLGImJmEhPT0hMSYmdGhpcy5xdWV1ZShhfHwiZngiLFtdKSx0aGlzLmVhY2goZnVuY3Rpb24oKXt2YXIgYj0hMCxlPW51bGwhPWEmJmErInF1ZXVlSG9va3MiLGY9bi50aW1lcnMsZz1OLmdldCh0aGlzKTtpZihlKWdbZV0mJmdbZV0uc3RvcCYmZChnW2VdKTtlbHNlIGZvcihlIGluIGcpZ1tlXSYmZ1tlXS5zdG9wJiZWYS50ZXN0KGUpJiZkKGdbZV0pO2ZvcihlPWYubGVuZ3RoO2UtLTspZltlXS5lbGVtIT09dGhpc3x8bnVsbCE9YSYmZltlXS5xdWV1ZSE9PWF8fChmW2VdLmFuaW0uc3RvcChjKSxiPSExLGYuc3BsaWNlKGUsMSkpOyFiJiZjfHxuLmRlcXVldWUodGhpcyxhKX0pfSxmaW5pc2g6ZnVuY3Rpb24oYSl7cmV0dXJuIGEhPT0hMSYmKGE9YXx8ImZ4IiksdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGIsYz1OLmdldCh0aGlzKSxkPWNbYSsicXVldWUiXSxlPWNbYSsicXVldWVIb29rcyJdLGY9bi50aW1lcnMsZz1kP2QubGVuZ3RoOjA7Zm9yKGMuZmluaXNoPSEwLG4ucXVldWUodGhpcyxhLFtdKSxlJiZlLnN0b3AmJmUuc3RvcC5jYWxsKHRoaXMsITApLGI9Zi5sZW5ndGg7Yi0tOylmW2JdLmVsZW09PT10aGlzJiZmW2JdLnF1ZXVlPT09YSYmKGZbYl0uYW5pbS5zdG9wKCEwKSxmLnNwbGljZShiLDEpKTtmb3IoYj0wO2c+YjtiKyspZFtiXSYmZFtiXS5maW5pc2gmJmRbYl0uZmluaXNoLmNhbGwodGhpcyk7ZGVsZXRlIGMuZmluaXNofSl9fSksbi5lYWNoKFsidG9nZ2xlIiwic2hvdyIsImhpZGUiXSxmdW5jdGlvbihhLGIpe3ZhciBjPW4uZm5bYl07bi5mbltiXT1mdW5jdGlvbihhLGQsZSl7cmV0dXJuIG51bGw9PWF8fCJib29sZWFuIj09dHlwZW9mIGE/Yy5hcHBseSh0aGlzLGFyZ3VtZW50cyk6dGhpcy5hbmltYXRlKFhhKGIsITApLGEsZCxlKX19KSxuLmVhY2goe3NsaWRlRG93bjpYYSgic2hvdyIpLHNsaWRlVXA6WGEoImhpZGUiKSxzbGlkZVRvZ2dsZTpYYSgidG9nZ2xlIiksZmFkZUluOntvcGFjaXR5OiJzaG93In0sZmFkZU91dDp7b3BhY2l0eToiaGlkZSJ9LGZhZGVUb2dnbGU6e29wYWNpdHk6InRvZ2dsZSJ9fSxmdW5jdGlvbihhLGIpe24uZm5bYV09ZnVuY3Rpb24oYSxjLGQpe3JldHVybiB0aGlzLmFuaW1hdGUoYixhLGMsZCl9fSksbi50aW1lcnM9W10sbi5meC50aWNrPWZ1bmN0aW9uKCl7dmFyIGEsYj0wLGM9bi50aW1lcnM7Zm9yKFNhPW4ubm93KCk7YjxjLmxlbmd0aDtiKyspYT1jW2JdLGEoKXx8Y1tiXSE9PWF8fGMuc3BsaWNlKGItLSwxKTtjLmxlbmd0aHx8bi5meC5zdG9wKCksU2E9dm9pZCAwfSxuLmZ4LnRpbWVyPWZ1bmN0aW9uKGEpe24udGltZXJzLnB1c2goYSksYSgpP24uZnguc3RhcnQoKTpuLnRpbWVycy5wb3AoKX0sbi5meC5pbnRlcnZhbD0xMyxuLmZ4LnN0YXJ0PWZ1bmN0aW9uKCl7VGF8fChUYT1hLnNldEludGVydmFsKG4uZngudGljayxuLmZ4LmludGVydmFsKSl9LG4uZnguc3RvcD1mdW5jdGlvbigpe2EuY2xlYXJJbnRlcnZhbChUYSksVGE9bnVsbH0sbi5meC5zcGVlZHM9e3Nsb3c6NjAwLGZhc3Q6MjAwLF9kZWZhdWx0OjQwMH0sbi5mbi5kZWxheT1mdW5jdGlvbihiLGMpe3JldHVybiBiPW4uZng/bi5meC5zcGVlZHNbYl18fGI6YixjPWN8fCJmeCIsdGhpcy5xdWV1ZShjLGZ1bmN0aW9uKGMsZCl7dmFyIGU9YS5zZXRUaW1lb3V0KGMsYik7ZC5zdG9wPWZ1bmN0aW9uKCl7YS5jbGVhclRpbWVvdXQoZSl9fSl9LGZ1bmN0aW9uKCl7dmFyIGE9ZC5jcmVhdGVFbGVtZW50KCJpbnB1dCIpLGI9ZC5jcmVhdGVFbGVtZW50KCJzZWxlY3QiKSxjPWIuYXBwZW5kQ2hpbGQoZC5jcmVhdGVFbGVtZW50KCJvcHRpb24iKSk7YS50eXBlPSJjaGVja2JveCIsbC5jaGVja09uPSIiIT09YS52YWx1ZSxsLm9wdFNlbGVjdGVkPWMuc2VsZWN0ZWQsYi5kaXNhYmxlZD0hMCxsLm9wdERpc2FibGVkPSFjLmRpc2FibGVkLGE9ZC5jcmVhdGVFbGVtZW50KCJpbnB1dCIpLGEudmFsdWU9InQiLGEudHlwZT0icmFkaW8iLGwucmFkaW9WYWx1ZT0idCI9PT1hLnZhbHVlfSgpO3ZhciBhYixiYj1uLmV4cHIuYXR0ckhhbmRsZTtuLmZuLmV4dGVuZCh7YXR0cjpmdW5jdGlvbihhLGIpe3JldHVybiBLKHRoaXMsbi5hdHRyLGEsYixhcmd1bWVudHMubGVuZ3RoPjEpfSxyZW1vdmVBdHRyOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXtuLnJlbW92ZUF0dHIodGhpcyxhKX0pfX0pLG4uZXh0ZW5kKHthdHRyOmZ1bmN0aW9uKGEsYixjKXt2YXIgZCxlLGY9YS5ub2RlVHlwZTtpZigzIT09ZiYmOCE9PWYmJjIhPT1mKXJldHVybiJ1bmRlZmluZWQiPT10eXBlb2YgYS5nZXRBdHRyaWJ1dGU/bi5wcm9wKGEsYixjKTooMT09PWYmJm4uaXNYTUxEb2MoYSl8fChiPWIudG9Mb3dlckNhc2UoKSxlPW4uYXR0ckhvb2tzW2JdfHwobi5leHByLm1hdGNoLmJvb2wudGVzdChiKT9hYjp2b2lkIDApKSx2b2lkIDAhPT1jP251bGw9PT1jP3ZvaWQgbi5yZW1vdmVBdHRyKGEsYik6ZSYmInNldCJpbiBlJiZ2b2lkIDAhPT0oZD1lLnNldChhLGMsYikpP2Q6KGEuc2V0QXR0cmlidXRlKGIsYysiIiksYyk6ZSYmImdldCJpbiBlJiZudWxsIT09KGQ9ZS5nZXQoYSxiKSk/ZDooZD1uLmZpbmQuYXR0cihhLGIpLG51bGw9PWQ/dm9pZCAwOmQpKX0sYXR0ckhvb2tzOnt0eXBlOntzZXQ6ZnVuY3Rpb24oYSxiKXtpZighbC5yYWRpb1ZhbHVlJiYicmFkaW8iPT09YiYmbi5ub2RlTmFtZShhLCJpbnB1dCIpKXt2YXIgYz1hLnZhbHVlO3JldHVybiBhLnNldEF0dHJpYnV0ZSgidHlwZSIsYiksYyYmKGEudmFsdWU9YyksYn19fX0scmVtb3ZlQXR0cjpmdW5jdGlvbihhLGIpe3ZhciBjLGQsZT0wLGY9YiYmYi5tYXRjaChHKTtpZihmJiYxPT09YS5ub2RlVHlwZSl3aGlsZShjPWZbZSsrXSlkPW4ucHJvcEZpeFtjXXx8YyxuLmV4cHIubWF0Y2guYm9vbC50ZXN0KGMpJiYoYVtkXT0hMSksYS5yZW1vdmVBdHRyaWJ1dGUoYyl9fSksYWI9e3NldDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGI9PT0hMT9uLnJlbW92ZUF0dHIoYSxjKTphLnNldEF0dHJpYnV0ZShjLGMpLGN9fSxuLmVhY2gobi5leHByLm1hdGNoLmJvb2wuc291cmNlLm1hdGNoKC9cdysvZyksZnVuY3Rpb24oYSxiKXt2YXIgYz1iYltiXXx8bi5maW5kLmF0dHI7YmJbYl09ZnVuY3Rpb24oYSxiLGQpe3ZhciBlLGY7cmV0dXJuIGR8fChmPWJiW2JdLGJiW2JdPWUsZT1udWxsIT1jKGEsYixkKT9iLnRvTG93ZXJDYXNlKCk6bnVsbCxiYltiXT1mKSxlfX0pO3ZhciBjYj0vXig/OmlucHV0fHNlbGVjdHx0ZXh0YXJlYXxidXR0b24pJC9pLGRiPS9eKD86YXxhcmVhKSQvaTtuLmZuLmV4dGVuZCh7cHJvcDpmdW5jdGlvbihhLGIpe3JldHVybiBLKHRoaXMsbi5wcm9wLGEsYixhcmd1bWVudHMubGVuZ3RoPjEpfSxyZW1vdmVQcm9wOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXtkZWxldGUgdGhpc1tuLnByb3BGaXhbYV18fGFdfSl9fSksbi5leHRlbmQoe3Byb3A6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkLGUsZj1hLm5vZGVUeXBlO2lmKDMhPT1mJiY4IT09ZiYmMiE9PWYpcmV0dXJuIDE9PT1mJiZuLmlzWE1MRG9jKGEpfHwoYj1uLnByb3BGaXhbYl18fGIsDQplPW4ucHJvcEhvb2tzW2JdKSx2b2lkIDAhPT1jP2UmJiJzZXQiaW4gZSYmdm9pZCAwIT09KGQ9ZS5zZXQoYSxjLGIpKT9kOmFbYl09YzplJiYiZ2V0ImluIGUmJm51bGwhPT0oZD1lLmdldChhLGIpKT9kOmFbYl19LHByb3BIb29rczp7dGFiSW5kZXg6e2dldDpmdW5jdGlvbihhKXt2YXIgYj1uLmZpbmQuYXR0cihhLCJ0YWJpbmRleCIpO3JldHVybiBiP3BhcnNlSW50KGIsMTApOmNiLnRlc3QoYS5ub2RlTmFtZSl8fGRiLnRlc3QoYS5ub2RlTmFtZSkmJmEuaHJlZj8wOi0xfX19LHByb3BGaXg6eyJmb3IiOiJodG1sRm9yIiwiY2xhc3MiOiJjbGFzc05hbWUifX0pLGwub3B0U2VsZWN0ZWR8fChuLnByb3BIb29rcy5zZWxlY3RlZD17Z2V0OmZ1bmN0aW9uKGEpe3ZhciBiPWEucGFyZW50Tm9kZTtyZXR1cm4gYiYmYi5wYXJlbnROb2RlJiZiLnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCxudWxsfSxzZXQ6ZnVuY3Rpb24oYSl7dmFyIGI9YS5wYXJlbnROb2RlO2ImJihiLnNlbGVjdGVkSW5kZXgsYi5wYXJlbnROb2RlJiZiLnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCl9fSksbi5lYWNoKFsidGFiSW5kZXgiLCJyZWFkT25seSIsIm1heExlbmd0aCIsImNlbGxTcGFjaW5nIiwiY2VsbFBhZGRpbmciLCJyb3dTcGFuIiwiY29sU3BhbiIsInVzZU1hcCIsImZyYW1lQm9yZGVyIiwiY29udGVudEVkaXRhYmxlIl0sZnVuY3Rpb24oKXtuLnByb3BGaXhbdGhpcy50b0xvd2VyQ2FzZSgpXT10aGlzfSk7dmFyIGViPS9bXHRcclxuXGZdL2c7ZnVuY3Rpb24gZmIoYSl7cmV0dXJuIGEuZ2V0QXR0cmlidXRlJiZhLmdldEF0dHJpYnV0ZSgiY2xhc3MiKXx8IiJ9bi5mbi5leHRlbmQoe2FkZENsYXNzOmZ1bmN0aW9uKGEpe3ZhciBiLGMsZCxlLGYsZyxoLGk9MDtpZihuLmlzRnVuY3Rpb24oYSkpcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbihiKXtuKHRoaXMpLmFkZENsYXNzKGEuY2FsbCh0aGlzLGIsZmIodGhpcykpKX0pO2lmKCJzdHJpbmciPT10eXBlb2YgYSYmYSl7Yj1hLm1hdGNoKEcpfHxbXTt3aGlsZShjPXRoaXNbaSsrXSlpZihlPWZiKGMpLGQ9MT09PWMubm9kZVR5cGUmJigiICIrZSsiICIpLnJlcGxhY2UoZWIsIiAiKSl7Zz0wO3doaWxlKGY9YltnKytdKWQuaW5kZXhPZigiICIrZisiICIpPDAmJihkKz1mKyIgIik7aD1uLnRyaW0oZCksZSE9PWgmJmMuc2V0QXR0cmlidXRlKCJjbGFzcyIsaCl9fXJldHVybiB0aGlzfSxyZW1vdmVDbGFzczpmdW5jdGlvbihhKXt2YXIgYixjLGQsZSxmLGcsaCxpPTA7aWYobi5pc0Z1bmN0aW9uKGEpKXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oYil7bih0aGlzKS5yZW1vdmVDbGFzcyhhLmNhbGwodGhpcyxiLGZiKHRoaXMpKSl9KTtpZighYXJndW1lbnRzLmxlbmd0aClyZXR1cm4gdGhpcy5hdHRyKCJjbGFzcyIsIiIpO2lmKCJzdHJpbmciPT10eXBlb2YgYSYmYSl7Yj1hLm1hdGNoKEcpfHxbXTt3aGlsZShjPXRoaXNbaSsrXSlpZihlPWZiKGMpLGQ9MT09PWMubm9kZVR5cGUmJigiICIrZSsiICIpLnJlcGxhY2UoZWIsIiAiKSl7Zz0wO3doaWxlKGY9YltnKytdKXdoaWxlKGQuaW5kZXhPZigiICIrZisiICIpPi0xKWQ9ZC5yZXBsYWNlKCIgIitmKyIgIiwiICIpO2g9bi50cmltKGQpLGUhPT1oJiZjLnNldEF0dHJpYnV0ZSgiY2xhc3MiLGgpfX1yZXR1cm4gdGhpc30sdG9nZ2xlQ2xhc3M6ZnVuY3Rpb24oYSxiKXt2YXIgYz10eXBlb2YgYTtyZXR1cm4iYm9vbGVhbiI9PXR5cGVvZiBiJiYic3RyaW5nIj09PWM/Yj90aGlzLmFkZENsYXNzKGEpOnRoaXMucmVtb3ZlQ2xhc3MoYSk6bi5pc0Z1bmN0aW9uKGEpP3RoaXMuZWFjaChmdW5jdGlvbihjKXtuKHRoaXMpLnRvZ2dsZUNsYXNzKGEuY2FsbCh0aGlzLGMsZmIodGhpcyksYiksYil9KTp0aGlzLmVhY2goZnVuY3Rpb24oKXt2YXIgYixkLGUsZjtpZigic3RyaW5nIj09PWMpe2Q9MCxlPW4odGhpcyksZj1hLm1hdGNoKEcpfHxbXTt3aGlsZShiPWZbZCsrXSllLmhhc0NsYXNzKGIpP2UucmVtb3ZlQ2xhc3MoYik6ZS5hZGRDbGFzcyhiKX1lbHNlIHZvaWQgMCE9PWEmJiJib29sZWFuIiE9PWN8fChiPWZiKHRoaXMpLGImJk4uc2V0KHRoaXMsIl9fY2xhc3NOYW1lX18iLGIpLHRoaXMuc2V0QXR0cmlidXRlJiZ0aGlzLnNldEF0dHJpYnV0ZSgiY2xhc3MiLGJ8fGE9PT0hMT8iIjpOLmdldCh0aGlzLCJfX2NsYXNzTmFtZV9fIil8fCIiKSl9KX0saGFzQ2xhc3M6ZnVuY3Rpb24oYSl7dmFyIGIsYyxkPTA7Yj0iICIrYSsiICI7d2hpbGUoYz10aGlzW2QrK10paWYoMT09PWMubm9kZVR5cGUmJigiICIrZmIoYykrIiAiKS5yZXBsYWNlKGViLCIgIikuaW5kZXhPZihiKT4tMSlyZXR1cm4hMDtyZXR1cm4hMX19KTt2YXIgZ2I9L1xyL2csaGI9L1tceDIwXHRcclxuXGZdKy9nO24uZm4uZXh0ZW5kKHt2YWw6ZnVuY3Rpb24oYSl7dmFyIGIsYyxkLGU9dGhpc1swXTt7aWYoYXJndW1lbnRzLmxlbmd0aClyZXR1cm4gZD1uLmlzRnVuY3Rpb24oYSksdGhpcy5lYWNoKGZ1bmN0aW9uKGMpe3ZhciBlOzE9PT10aGlzLm5vZGVUeXBlJiYoZT1kP2EuY2FsbCh0aGlzLGMsbih0aGlzKS52YWwoKSk6YSxudWxsPT1lP2U9IiI6Im51bWJlciI9PXR5cGVvZiBlP2UrPSIiOm4uaXNBcnJheShlKSYmKGU9bi5tYXAoZSxmdW5jdGlvbihhKXtyZXR1cm4gbnVsbD09YT8iIjphKyIifSkpLGI9bi52YWxIb29rc1t0aGlzLnR5cGVdfHxuLnZhbEhvb2tzW3RoaXMubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0sYiYmInNldCJpbiBiJiZ2b2lkIDAhPT1iLnNldCh0aGlzLGUsInZhbHVlIil8fCh0aGlzLnZhbHVlPWUpKX0pO2lmKGUpcmV0dXJuIGI9bi52YWxIb29rc1tlLnR5cGVdfHxuLnZhbEhvb2tzW2Uubm9kZU5hbWUudG9Mb3dlckNhc2UoKV0sYiYmImdldCJpbiBiJiZ2b2lkIDAhPT0oYz1iLmdldChlLCJ2YWx1ZSIpKT9jOihjPWUudmFsdWUsInN0cmluZyI9PXR5cGVvZiBjP2MucmVwbGFjZShnYiwiIik6bnVsbD09Yz8iIjpjKX19fSksbi5leHRlbmQoe3ZhbEhvb2tzOntvcHRpb246e2dldDpmdW5jdGlvbihhKXt2YXIgYj1uLmZpbmQuYXR0cihhLCJ2YWx1ZSIpO3JldHVybiBudWxsIT1iP2I6bi50cmltKG4udGV4dChhKSkucmVwbGFjZShoYiwiICIpfX0sc2VsZWN0OntnZXQ6ZnVuY3Rpb24oYSl7Zm9yKHZhciBiLGMsZD1hLm9wdGlvbnMsZT1hLnNlbGVjdGVkSW5kZXgsZj0ic2VsZWN0LW9uZSI9PT1hLnR5cGV8fDA+ZSxnPWY/bnVsbDpbXSxoPWY/ZSsxOmQubGVuZ3RoLGk9MD5lP2g6Zj9lOjA7aD5pO2krKylpZihjPWRbaV0sKGMuc2VsZWN0ZWR8fGk9PT1lKSYmKGwub3B0RGlzYWJsZWQ/IWMuZGlzYWJsZWQ6bnVsbD09PWMuZ2V0QXR0cmlidXRlKCJkaXNhYmxlZCIpKSYmKCFjLnBhcmVudE5vZGUuZGlzYWJsZWR8fCFuLm5vZGVOYW1lKGMucGFyZW50Tm9kZSwib3B0Z3JvdXAiKSkpe2lmKGI9bihjKS52YWwoKSxmKXJldHVybiBiO2cucHVzaChiKX1yZXR1cm4gZ30sc2V0OmZ1bmN0aW9uKGEsYil7dmFyIGMsZCxlPWEub3B0aW9ucyxmPW4ubWFrZUFycmF5KGIpLGc9ZS5sZW5ndGg7d2hpbGUoZy0tKWQ9ZVtnXSwoZC5zZWxlY3RlZD1uLmluQXJyYXkobi52YWxIb29rcy5vcHRpb24uZ2V0KGQpLGYpPi0xKSYmKGM9ITApO3JldHVybiBjfHwoYS5zZWxlY3RlZEluZGV4PS0xKSxmfX19fSksbi5lYWNoKFsicmFkaW8iLCJjaGVja2JveCJdLGZ1bmN0aW9uKCl7bi52YWxIb29rc1t0aGlzXT17c2V0OmZ1bmN0aW9uKGEsYil7cmV0dXJuIG4uaXNBcnJheShiKT9hLmNoZWNrZWQ9bi5pbkFycmF5KG4oYSkudmFsKCksYik+LTE6dm9pZCAwfX0sbC5jaGVja09ufHwobi52YWxIb29rc1t0aGlzXS5nZXQ9ZnVuY3Rpb24oYSl7cmV0dXJuIG51bGw9PT1hLmdldEF0dHJpYnV0ZSgidmFsdWUiKT8ib24iOmEudmFsdWV9KX0pO3ZhciBpYj0vXig/OmZvY3VzaW5mb2N1c3xmb2N1c291dGJsdXIpJC87bi5leHRlbmQobi5ldmVudCx7dHJpZ2dlcjpmdW5jdGlvbihiLGMsZSxmKXt2YXIgZyxoLGksaixsLG0sbyxwPVtlfHxkXSxxPWsuY2FsbChiLCJ0eXBlIik/Yi50eXBlOmIscj1rLmNhbGwoYiwibmFtZXNwYWNlIik/Yi5uYW1lc3BhY2Uuc3BsaXQoIi4iKTpbXTtpZihoPWk9ZT1lfHxkLDMhPT1lLm5vZGVUeXBlJiY4IT09ZS5ub2RlVHlwZSYmIWliLnRlc3QocStuLmV2ZW50LnRyaWdnZXJlZCkmJihxLmluZGV4T2YoIi4iKT4tMSYmKHI9cS5zcGxpdCgiLiIpLHE9ci5zaGlmdCgpLHIuc29ydCgpKSxsPXEuaW5kZXhPZigiOiIpPDAmJiJvbiIrcSxiPWJbbi5leHBhbmRvXT9iOm5ldyBuLkV2ZW50KHEsIm9iamVjdCI9PXR5cGVvZiBiJiZiKSxiLmlzVHJpZ2dlcj1mPzI6MyxiLm5hbWVzcGFjZT1yLmpvaW4oIi4iKSxiLnJuYW1lc3BhY2U9Yi5uYW1lc3BhY2U/bmV3IFJlZ0V4cCgiKF58XFwuKSIrci5qb2luKCJcXC4oPzouKlxcLnwpIikrIihcXC58JCkiKTpudWxsLGIucmVzdWx0PXZvaWQgMCxiLnRhcmdldHx8KGIudGFyZ2V0PWUpLGM9bnVsbD09Yz9bYl06bi5tYWtlQXJyYXkoYyxbYl0pLG89bi5ldmVudC5zcGVjaWFsW3FdfHx7fSxmfHwhby50cmlnZ2VyfHxvLnRyaWdnZXIuYXBwbHkoZSxjKSE9PSExKSl7aWYoIWYmJiFvLm5vQnViYmxlJiYhbi5pc1dpbmRvdyhlKSl7Zm9yKGo9by5kZWxlZ2F0ZVR5cGV8fHEsaWIudGVzdChqK3EpfHwoaD1oLnBhcmVudE5vZGUpO2g7aD1oLnBhcmVudE5vZGUpcC5wdXNoKGgpLGk9aDtpPT09KGUub3duZXJEb2N1bWVudHx8ZCkmJnAucHVzaChpLmRlZmF1bHRWaWV3fHxpLnBhcmVudFdpbmRvd3x8YSl9Zz0wO3doaWxlKChoPXBbZysrXSkmJiFiLmlzUHJvcGFnYXRpb25TdG9wcGVkKCkpYi50eXBlPWc+MT9qOm8uYmluZFR5cGV8fHEsbT0oTi5nZXQoaCwiZXZlbnRzIil8fHt9KVtiLnR5cGVdJiZOLmdldChoLCJoYW5kbGUiKSxtJiZtLmFwcGx5KGgsYyksbT1sJiZoW2xdLG0mJm0uYXBwbHkmJkwoaCkmJihiLnJlc3VsdD1tLmFwcGx5KGgsYyksYi5yZXN1bHQ9PT0hMSYmYi5wcmV2ZW50RGVmYXVsdCgpKTtyZXR1cm4gYi50eXBlPXEsZnx8Yi5pc0RlZmF1bHRQcmV2ZW50ZWQoKXx8by5fZGVmYXVsdCYmby5fZGVmYXVsdC5hcHBseShwLnBvcCgpLGMpIT09ITF8fCFMKGUpfHxsJiZuLmlzRnVuY3Rpb24oZVtxXSkmJiFuLmlzV2luZG93KGUpJiYoaT1lW2xdLGkmJihlW2xdPW51bGwpLG4uZXZlbnQudHJpZ2dlcmVkPXEsZVtxXSgpLG4uZXZlbnQudHJpZ2dlcmVkPXZvaWQgMCxpJiYoZVtsXT1pKSksYi5yZXN1bHR9fSxzaW11bGF0ZTpmdW5jdGlvbihhLGIsYyl7dmFyIGQ9bi5leHRlbmQobmV3IG4uRXZlbnQsYyx7dHlwZTphLGlzU2ltdWxhdGVkOiEwfSk7bi5ldmVudC50cmlnZ2VyKGQsbnVsbCxiKSxkLmlzRGVmYXVsdFByZXZlbnRlZCgpJiZjLnByZXZlbnREZWZhdWx0KCl9fSksbi5mbi5leHRlbmQoe3RyaWdnZXI6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7bi5ldmVudC50cmlnZ2VyKGEsYix0aGlzKX0pfSx0cmlnZ2VySGFuZGxlcjpmdW5jdGlvbihhLGIpe3ZhciBjPXRoaXNbMF07cmV0dXJuIGM/bi5ldmVudC50cmlnZ2VyKGEsYixjLCEwKTp2b2lkIDB9fSksbi5lYWNoKCJibHVyIGZvY3VzIGZvY3VzaW4gZm9jdXNvdXQgbG9hZCByZXNpemUgc2Nyb2xsIHVubG9hZCBjbGljayBkYmxjbGljayBtb3VzZWRvd24gbW91c2V1cCBtb3VzZW1vdmUgbW91c2VvdmVyIG1vdXNlb3V0IG1vdXNlZW50ZXIgbW91c2VsZWF2ZSBjaGFuZ2Ugc2VsZWN0IHN1Ym1pdCBrZXlkb3duIGtleXByZXNzIGtleXVwIGVycm9yIGNvbnRleHRtZW51Ii5zcGxpdCgiICIpLGZ1bmN0aW9uKGEsYil7bi5mbltiXT1mdW5jdGlvbihhLGMpe3JldHVybiBhcmd1bWVudHMubGVuZ3RoPjA/dGhpcy5vbihiLG51bGwsYSxjKTp0aGlzLnRyaWdnZXIoYil9fSksbi5mbi5leHRlbmQoe2hvdmVyOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMubW91c2VlbnRlcihhKS5tb3VzZWxlYXZlKGJ8fGEpfX0pLGwuZm9jdXNpbj0ib25mb2N1c2luImluIGEsbC5mb2N1c2lufHxuLmVhY2goe2ZvY3VzOiJmb2N1c2luIixibHVyOiJmb2N1c291dCJ9LGZ1bmN0aW9uKGEsYil7dmFyIGM9ZnVuY3Rpb24oYSl7bi5ldmVudC5zaW11bGF0ZShiLGEudGFyZ2V0LG4uZXZlbnQuZml4KGEpKX07bi5ldmVudC5zcGVjaWFsW2JdPXtzZXR1cDpmdW5jdGlvbigpe3ZhciBkPXRoaXMub3duZXJEb2N1bWVudHx8dGhpcyxlPU4uYWNjZXNzKGQsYik7ZXx8ZC5hZGRFdmVudExpc3RlbmVyKGEsYywhMCksTi5hY2Nlc3MoZCxiLChlfHwwKSsxKX0sdGVhcmRvd246ZnVuY3Rpb24oKXt2YXIgZD10aGlzLm93bmVyRG9jdW1lbnR8fHRoaXMsZT1OLmFjY2VzcyhkLGIpLTE7ZT9OLmFjY2VzcyhkLGIsZSk6KGQucmVtb3ZlRXZlbnRMaXN0ZW5lcihhLGMsITApLE4ucmVtb3ZlKGQsYikpfX19KTt2YXIgamI9YS5sb2NhdGlvbixrYj1uLm5vdygpLGxiPS9cPy87bi5wYXJzZUpTT049ZnVuY3Rpb24oYSl7cmV0dXJuIEpTT04ucGFyc2UoYSsiIil9LG4ucGFyc2VYTUw9ZnVuY3Rpb24oYil7dmFyIGM7aWYoIWJ8fCJzdHJpbmciIT10eXBlb2YgYilyZXR1cm4gbnVsbDt0cnl7Yz0obmV3IGEuRE9NUGFyc2VyKS5wYXJzZUZyb21TdHJpbmcoYiwidGV4dC94bWwiKX1jYXRjaChkKXtjPXZvaWQgMH1yZXR1cm4gYyYmIWMuZ2V0RWxlbWVudHNCeVRhZ05hbWUoInBhcnNlcmVycm9yIikubGVuZ3RofHxuLmVycm9yKCJJbnZhbGlkIFhNTDogIitiKSxjfTt2YXIgbWI9LyMuKiQvLG5iPS8oWz8mXSlfPVteJl0qLyxvYj0vXiguKj8pOlsgXHRdKihbXlxyXG5dKikkL2dtLHBiPS9eKD86YWJvdXR8YXBwfGFwcC1zdG9yYWdlfC4rLWV4dGVuc2lvbnxmaWxlfHJlc3x3aWRnZXQpOiQvLHFiPS9eKD86R0VUfEhFQUQpJC8scmI9L15cL1wvLyxzYj17fSx0Yj17fSx1Yj0iKi8iLmNvbmNhdCgiKiIpLHZiPWQuY3JlYXRlRWxlbWVudCgiYSIpO3ZiLmhyZWY9amIuaHJlZjtmdW5jdGlvbiB3YihhKXtyZXR1cm4gZnVuY3Rpb24oYixjKXsic3RyaW5nIiE9dHlwZW9mIGImJihjPWIsYj0iKiIpO3ZhciBkLGU9MCxmPWIudG9Mb3dlckNhc2UoKS5tYXRjaChHKXx8W107aWYobi5pc0Z1bmN0aW9uKGMpKXdoaWxlKGQ9ZltlKytdKSIrIj09PWRbMF0/KGQ9ZC5zbGljZSgxKXx8IioiLChhW2RdPWFbZF18fFtdKS51bnNoaWZ0KGMpKTooYVtkXT1hW2RdfHxbXSkucHVzaChjKX19ZnVuY3Rpb24geGIoYSxiLGMsZCl7dmFyIGU9e30sZj1hPT09dGI7ZnVuY3Rpb24gZyhoKXt2YXIgaTtyZXR1cm4gZVtoXT0hMCxuLmVhY2goYVtoXXx8W10sZnVuY3Rpb24oYSxoKXt2YXIgaj1oKGIsYyxkKTtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIGp8fGZ8fGVbal0/Zj8hKGk9aik6dm9pZCAwOihiLmRhdGFUeXBlcy51bnNoaWZ0KGopLGcoaiksITEpfSksaX1yZXR1cm4gZyhiLmRhdGFUeXBlc1swXSl8fCFlWyIqIl0mJmcoIioiKX1mdW5jdGlvbiB5YihhLGIpe3ZhciBjLGQsZT1uLmFqYXhTZXR0aW5ncy5mbGF0T3B0aW9uc3x8e307Zm9yKGMgaW4gYil2b2lkIDAhPT1iW2NdJiYoKGVbY10/YTpkfHwoZD17fSkpW2NdPWJbY10pO3JldHVybiBkJiZuLmV4dGVuZCghMCxhLGQpLGF9ZnVuY3Rpb24gemIoYSxiLGMpe3ZhciBkLGUsZixnLGg9YS5jb250ZW50cyxpPWEuZGF0YVR5cGVzO3doaWxlKCIqIj09PWlbMF0paS5zaGlmdCgpLHZvaWQgMD09PWQmJihkPWEubWltZVR5cGV8fGIuZ2V0UmVzcG9uc2VIZWFkZXIoIkNvbnRlbnQtVHlwZSIpKTtpZihkKWZvcihlIGluIGgpaWYoaFtlXSYmaFtlXS50ZXN0KGQpKXtpLnVuc2hpZnQoZSk7YnJlYWt9aWYoaVswXWluIGMpZj1pWzBdO2Vsc2V7Zm9yKGUgaW4gYyl7aWYoIWlbMF18fGEuY29udmVydGVyc1tlKyIgIitpWzBdXSl7Zj1lO2JyZWFrfWd8fChnPWUpfWY9Znx8Z31yZXR1cm4gZj8oZiE9PWlbMF0mJmkudW5zaGlmdChmKSxjW2ZdKTp2b2lkIDB9ZnVuY3Rpb24gQWIoYSxiLGMsZCl7dmFyIGUsZixnLGgsaSxqPXt9LGs9YS5kYXRhVHlwZXMuc2xpY2UoKTtpZihrWzFdKWZvcihnIGluIGEuY29udmVydGVycylqW2cudG9Mb3dlckNhc2UoKV09YS5jb252ZXJ0ZXJzW2ddO2Y9ay5zaGlmdCgpO3doaWxlKGYpaWYoYS5yZXNwb25zZUZpZWxkc1tmXSYmKGNbYS5yZXNwb25zZUZpZWxkc1tmXV09YiksIWkmJmQmJmEuZGF0YUZpbHRlciYmKGI9YS5kYXRhRmlsdGVyKGIsYS5kYXRhVHlwZSkpLGk9ZixmPWsuc2hpZnQoKSlpZigiKiI9PT1mKWY9aTtlbHNlIGlmKCIqIiE9PWkmJmkhPT1mKXtpZihnPWpbaSsiICIrZl18fGpbIiogIitmXSwhZylmb3IoZSBpbiBqKWlmKGg9ZS5zcGxpdCgiICIpLGhbMV09PT1mJiYoZz1qW2krIiAiK2hbMF1dfHxqWyIqICIraFswXV0pKXtnPT09ITA/Zz1qW2VdOmpbZV0hPT0hMCYmKGY9aFswXSxrLnVuc2hpZnQoaFsxXSkpO2JyZWFrfWlmKGchPT0hMClpZihnJiZhWyJ0aHJvd3MiXSliPWcoYik7ZWxzZSB0cnl7Yj1nKGIpfWNhdGNoKGwpe3JldHVybntzdGF0ZToicGFyc2VyZXJyb3IiLGVycm9yOmc/bDoiTm8gY29udmVyc2lvbiBmcm9tICIraSsiIHRvICIrZn19fXJldHVybntzdGF0ZToic3VjY2VzcyIsZGF0YTpifX1uLmV4dGVuZCh7YWN0aXZlOjAsbGFzdE1vZGlmaWVkOnt9LGV0YWc6e30sYWpheFNldHRpbmdzOnt1cmw6amIuaHJlZix0eXBlOiJHRVQiLGlzTG9jYWw6cGIudGVzdChqYi5wcm90b2NvbCksZ2xvYmFsOiEwLHByb2Nlc3NEYXRhOiEwLGFzeW5jOiEwLGNvbnRlbnRUeXBlOiJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7IGNoYXJzZXQ9VVRGLTgiLGFjY2VwdHM6eyIqIjp1Yix0ZXh0OiJ0ZXh0L3BsYWluIixodG1sOiJ0ZXh0L2h0bWwiLHhtbDoiYXBwbGljYXRpb24veG1sLCB0ZXh0L3htbCIsanNvbjoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9qYXZhc2NyaXB0In0sY29udGVudHM6e3htbDovXGJ4bWxcYi8saHRtbDovXGJodG1sLyxqc29uOi9cYmpzb25cYi99LHJlc3BvbnNlRmllbGRzOnt4bWw6InJlc3BvbnNlWE1MIix0ZXh0OiJyZXNwb25zZVRleHQiLGpzb246InJlc3BvbnNlSlNPTiJ9LGNvbnZlcnRlcnM6eyIqIHRleHQiOlN0cmluZywidGV4dCBodG1sIjohMCwidGV4dCBqc29uIjpuLnBhcnNlSlNPTiwidGV4dCB4bWwiOm4ucGFyc2VYTUx9LGZsYXRPcHRpb25zOnt1cmw6ITAsY29udGV4dDohMH19LGFqYXhTZXR1cDpmdW5jdGlvbihhLGIpe3JldHVybiBiP3liKHliKGEsbi5hamF4U2V0dGluZ3MpLGIpOnliKG4uYWpheFNldHRpbmdzLGEpfSxhamF4UHJlZmlsdGVyOndiKHNiKSxhamF4VHJhbnNwb3J0OndiKHRiKSxhamF4OmZ1bmN0aW9uKGIsYyl7Im9iamVjdCI9PXR5cGVvZiBiJiYoYz1iLGI9dm9pZCAwKSxjPWN8fHt9O3ZhciBlLGYsZyxoLGksaixrLGwsbT1uLmFqYXhTZXR1cCh7fSxjKSxvPW0uY29udGV4dHx8bSxwPW0uY29udGV4dCYmKG8ubm9kZVR5cGV8fG8uanF1ZXJ5KT9uKG8pOm4uZXZlbnQscT1uLkRlZmVycmVkKCkscj1uLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSxzPW0uc3RhdHVzQ29kZXx8e30sdD17fSx1PXt9LHY9MCx3PSJjYW5jZWxlZCIseD17cmVhZHlTdGF0ZTowLGdldFJlc3BvbnNlSGVhZGVyOmZ1bmN0aW9uKGEpe3ZhciBiO2lmKDI9PT12KXtpZighaCl7aD17fTt3aGlsZShiPW9iLmV4ZWMoZykpaFtiWzFdLnRvTG93ZXJDYXNlKCldPWJbMl19Yj1oW2EudG9Mb3dlckNhc2UoKV19cmV0dXJuIG51bGw9PWI/bnVsbDpifSxnZXRBbGxSZXNwb25zZUhlYWRlcnM6ZnVuY3Rpb24oKXtyZXR1cm4gMj09PXY/ZzpudWxsfSxzZXRSZXF1ZXN0SGVhZGVyOmZ1bmN0aW9uKGEsYil7dmFyIGM9YS50b0xvd2VyQ2FzZSgpO3JldHVybiB2fHwoYT11W2NdPXVbY118fGEsdFthXT1iKSx0aGlzfSxvdmVycmlkZU1pbWVUeXBlOmZ1bmN0aW9uKGEpe3JldHVybiB2fHwobS5taW1lVHlwZT1hKSx0aGlzfSxzdGF0dXNDb2RlOmZ1bmN0aW9uKGEpe3ZhciBiO2lmKGEpaWYoMj52KWZvcihiIGluIGEpc1tiXT1bc1tiXSxhW2JdXTtlbHNlIHguYWx3YXlzKGFbeC5zdGF0dXNdKTtyZXR1cm4gdGhpc30sYWJvcnQ6ZnVuY3Rpb24oYSl7dmFyIGI9YXx8dztyZXR1cm4gZSYmZS5hYm9ydChiKSx6KDAsYiksdGhpc319O2lmKHEucHJvbWlzZSh4KS5jb21wbGV0ZT1yLmFkZCx4LnN1Y2Nlc3M9eC5kb25lLHguZXJyb3I9eC5mYWlsLG0udXJsPSgoYnx8bS51cmx8fGpiLmhyZWYpKyIiKS5yZXBsYWNlKG1iLCIiKS5yZXBsYWNlKHJiLGpiLnByb3RvY29sKyIvLyIpLG0udHlwZT1jLm1ldGhvZHx8Yy50eXBlfHxtLm1ldGhvZHx8bS50eXBlLG0uZGF0YVR5cGVzPW4udHJpbShtLmRhdGFUeXBlfHwiKiIpLnRvTG93ZXJDYXNlKCkubWF0Y2goRyl8fFsiIl0sbnVsbD09bS5jcm9zc0RvbWFpbil7aj1kLmNyZWF0ZUVsZW1lbnQoImEiKTt0cnl7ai5ocmVmPW0udXJsLGouaHJlZj1qLmhyZWYsbS5jcm9zc0RvbWFpbj12Yi5wcm90b2NvbCsiLy8iK3ZiLmhvc3QhPWoucHJvdG9jb2wrIi8vIitqLmhvc3R9Y2F0Y2goeSl7bS5jcm9zc0RvbWFpbj0hMH19aWYobS5kYXRhJiZtLnByb2Nlc3NEYXRhJiYic3RyaW5nIiE9dHlwZW9mIG0uZGF0YSYmKG0uZGF0YT1uLnBhcmFtKG0uZGF0YSxtLnRyYWRpdGlvbmFsKSkseGIoc2IsbSxjLHgpLDI9PT12KXJldHVybiB4O2s9bi5ldmVudCYmbS5nbG9iYWwsayYmMD09PW4uYWN0aXZlKysmJm4uZXZlbnQudHJpZ2dlcigiYWpheFN0YXJ0IiksbS50eXBlPW0udHlwZS50b1VwcGVyQ2FzZSgpLG0uaGFzQ29udGVudD0hcWIudGVzdChtLnR5cGUpLGY9bS51cmwsbS5oYXNDb250ZW50fHwobS5kYXRhJiYoZj1tLnVybCs9KGxiLnRlc3QoZik/IiYiOiI/IikrbS5kYXRhLGRlbGV0ZSBtLmRhdGEpLG0uY2FjaGU9PT0hMSYmKG0udXJsPW5iLnRlc3QoZik/Zi5yZXBsYWNlKG5iLCIkMV89IitrYisrKTpmKyhsYi50ZXN0KGYpPyImIjoiPyIpKyJfPSIra2IrKykpLG0uaWZNb2RpZmllZCYmKG4ubGFzdE1vZGlmaWVkW2ZdJiZ4LnNldFJlcXVlc3RIZWFkZXIoIklmLU1vZGlmaWVkLVNpbmNlIixuLmxhc3RNb2RpZmllZFtmXSksbi5ldGFnW2ZdJiZ4LnNldFJlcXVlc3RIZWFkZXIoIklmLU5vbmUtTWF0Y2giLG4uZXRhZ1tmXSkpLChtLmRhdGEmJm0uaGFzQ29udGVudCYmbS5jb250ZW50VHlwZSE9PSExfHxjLmNvbnRlbnRUeXBlKSYmeC5zZXRSZXF1ZXN0SGVhZGVyKCJDb250ZW50LVR5cGUiLG0uY29udGVudFR5cGUpLHguc2V0UmVxdWVzdEhlYWRlcigiQWNjZXB0IixtLmRhdGFUeXBlc1swXSYmbS5hY2NlcHRzW20uZGF0YVR5cGVzWzBdXT9tLmFjY2VwdHNbbS5kYXRhVHlwZXNbMF1dKygiKiIhPT1tLmRhdGFUeXBlc1swXT8iLCAiK3ViKyI7IHE9MC4wMSI6IiIpOm0uYWNjZXB0c1siKiJdKTtmb3IobCBpbiBtLmhlYWRlcnMpeC5zZXRSZXF1ZXN0SGVhZGVyKGwsbS5oZWFkZXJzW2xdKTtpZihtLmJlZm9yZVNlbmQmJihtLmJlZm9yZVNlbmQuY2FsbChvLHgsbSk9PT0hMXx8Mj09PXYpKXJldHVybiB4LmFib3J0KCk7dz0iYWJvcnQiO2ZvcihsIGlue3N1Y2Nlc3M6MSxlcnJvcjoxLGNvbXBsZXRlOjF9KXhbbF0obVtsXSk7aWYoZT14Yih0YixtLGMseCkpe2lmKHgucmVhZHlTdGF0ZT0xLGsmJnAudHJpZ2dlcigiYWpheFNlbmQiLFt4LG1dKSwyPT09dilyZXR1cm4geDttLmFzeW5jJiZtLnRpbWVvdXQ+MCYmKGk9YS5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7eC5hYm9ydCgidGltZW91dCIpfSxtLnRpbWVvdXQpKTt0cnl7dj0xLGUuc2VuZCh0LHopfWNhdGNoKHkpe2lmKCEoMj52KSl0aHJvdyB5O3ooLTEseSl9fWVsc2UgeigtMSwiTm8gVHJhbnNwb3J0Iik7ZnVuY3Rpb24geihiLGMsZCxoKXt2YXIgaixsLHQsdSx3LHk9YzsyIT09diYmKHY9MixpJiZhLmNsZWFyVGltZW91dChpKSxlPXZvaWQgMCxnPWh8fCIiLHgucmVhZHlTdGF0ZT1iPjA/NDowLGo9Yj49MjAwJiYzMDA+Ynx8MzA0PT09YixkJiYodT16YihtLHgsZCkpLHU9QWIobSx1LHgsaiksaj8obS5pZk1vZGlmaWVkJiYodz14LmdldFJlc3BvbnNlSGVhZGVyKCJMYXN0LU1vZGlmaWVkIiksdyYmKG4ubGFzdE1vZGlmaWVkW2ZdPXcpLHc9eC5nZXRSZXNwb25zZUhlYWRlcigiZXRhZyIpLHcmJihuLmV0YWdbZl09dykpLDIwND09PWJ8fCJIRUFEIj09PW0udHlwZT95PSJub2NvbnRlbnQiOjMwND09PWI/eT0ibm90bW9kaWZpZWQiOih5PXUuc3RhdGUsbD11LmRhdGEsdD11LmVycm9yLGo9IXQpKToodD15LCFiJiZ5fHwoeT0iZXJyb3IiLDA+YiYmKGI9MCkpKSx4LnN0YXR1cz1iLHguc3RhdHVzVGV4dD0oY3x8eSkrIiIsaj9xLnJlc29sdmVXaXRoKG8sW2wseSx4XSk6cS5yZWplY3RXaXRoKG8sW3gseSx0XSkseC5zdGF0dXNDb2RlKHMpLHM9dm9pZCAwLGsmJnAudHJpZ2dlcihqPyJhamF4U3VjY2VzcyI6ImFqYXhFcnJvciIsW3gsbSxqP2w6dF0pLHIuZmlyZVdpdGgobyxbeCx5XSksayYmKHAudHJpZ2dlcigiYWpheENvbXBsZXRlIixbeCxtXSksLS1uLmFjdGl2ZXx8bi5ldmVudC50cmlnZ2VyKCJhamF4U3RvcCIpKSl9cmV0dXJuIHh9LGdldEpTT046ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBuLmdldChhLGIsYywianNvbiIpfSxnZXRTY3JpcHQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbi5nZXQoYSx2b2lkIDAsYiwic2NyaXB0Iil9fSksbi5lYWNoKFsiZ2V0IiwicG9zdCJdLGZ1bmN0aW9uKGEsYil7bltiXT1mdW5jdGlvbihhLGMsZCxlKXtyZXR1cm4gbi5pc0Z1bmN0aW9uKGMpJiYoZT1lfHxkLGQ9YyxjPXZvaWQgMCksbi5hamF4KG4uZXh0ZW5kKHt1cmw6YSx0eXBlOmIsZGF0YVR5cGU6ZSxkYXRhOmMsc3VjY2VzczpkfSxuLmlzUGxhaW5PYmplY3QoYSkmJmEpKX19KSxuLl9ldmFsVXJsPWZ1bmN0aW9uKGEpe3JldHVybiBuLmFqYXgoe3VybDphLHR5cGU6IkdFVCIsZGF0YVR5cGU6InNjcmlwdCIsYXN5bmM6ITEsZ2xvYmFsOiExLCJ0aHJvd3MiOiEwfSl9LG4uZm4uZXh0ZW5kKHt3cmFwQWxsOmZ1bmN0aW9uKGEpe3ZhciBiO3JldHVybiBuLmlzRnVuY3Rpb24oYSk/dGhpcy5lYWNoKGZ1bmN0aW9uKGIpe24odGhpcykud3JhcEFsbChhLmNhbGwodGhpcyxiKSl9KToodGhpc1swXSYmKGI9bihhLHRoaXNbMF0ub3duZXJEb2N1bWVudCkuZXEoMCkuY2xvbmUoITApLHRoaXNbMF0ucGFyZW50Tm9kZSYmYi5pbnNlcnRCZWZvcmUodGhpc1swXSksYi5tYXAoZnVuY3Rpb24oKXt2YXIgYT10aGlzO3doaWxlKGEuZmlyc3RFbGVtZW50Q2hpbGQpYT1hLmZpcnN0RWxlbWVudENoaWxkO3JldHVybiBhfSkuYXBwZW5kKHRoaXMpKSx0aGlzKX0sd3JhcElubmVyOmZ1bmN0aW9uKGEpe3JldHVybiBuLmlzRnVuY3Rpb24oYSk/dGhpcy5lYWNoKGZ1bmN0aW9uKGIpe24odGhpcykud3JhcElubmVyKGEuY2FsbCh0aGlzLGIpKX0pOnRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBiPW4odGhpcyksYz1iLmNvbnRlbnRzKCk7Yy5sZW5ndGg/Yy53cmFwQWxsKGEpOmIuYXBwZW5kKGEpfSl9LHdyYXA6ZnVuY3Rpb24oYSl7dmFyIGI9bi5pc0Z1bmN0aW9uKGEpO3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oYyl7bih0aGlzKS53cmFwQWxsKGI/YS5jYWxsKHRoaXMsYyk6YSl9KX0sdW53cmFwOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucGFyZW50KCkuZWFjaChmdW5jdGlvbigpe24ubm9kZU5hbWUodGhpcywiYm9keSIpfHxuKHRoaXMpLnJlcGxhY2VXaXRoKHRoaXMuY2hpbGROb2Rlcyl9KS5lbmQoKX19KSxuLmV4cHIuZmlsdGVycy5oaWRkZW49ZnVuY3Rpb24oYSl7cmV0dXJuIW4uZXhwci5maWx0ZXJzLnZpc2libGUoYSl9LG4uZXhwci5maWx0ZXJzLnZpc2libGU9ZnVuY3Rpb24oYSl7cmV0dXJuIGEub2Zmc2V0V2lkdGg+MHx8YS5vZmZzZXRIZWlnaHQ+MHx8YS5nZXRDbGllbnRSZWN0cygpLmxlbmd0aD4wfTt2YXIgQmI9LyUyMC9nLENiPS9cW1xdJC8sRGI9L1xyP1xuL2csRWI9L14oPzpzdWJtaXR8YnV0dG9ufGltYWdlfHJlc2V0fGZpbGUpJC9pLEZiPS9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGtleWdlbikvaTtmdW5jdGlvbiBHYihhLGIsYyxkKXt2YXIgZTtpZihuLmlzQXJyYXkoYikpbi5lYWNoKGIsZnVuY3Rpb24oYixlKXtjfHxDYi50ZXN0KGEpP2QoYSxlKTpHYihhKyJbIisoIm9iamVjdCI9PXR5cGVvZiBlJiZudWxsIT1lP2I6IiIpKyJdIixlLGMsZCl9KTtlbHNlIGlmKGN8fCJvYmplY3QiIT09bi50eXBlKGIpKWQoYSxiKTtlbHNlIGZvcihlIGluIGIpR2IoYSsiWyIrZSsiXSIsYltlXSxjLGQpfW4ucGFyYW09ZnVuY3Rpb24oYSxiKXt2YXIgYyxkPVtdLGU9ZnVuY3Rpb24oYSxiKXtiPW4uaXNGdW5jdGlvbihiKT9iKCk6bnVsbD09Yj8iIjpiLGRbZC5sZW5ndGhdPWVuY29kZVVSSUNvbXBvbmVudChhKSsiPSIrZW5jb2RlVVJJQ29tcG9uZW50KGIpfTtpZih2b2lkIDA9PT1iJiYoYj1uLmFqYXhTZXR0aW5ncyYmbi5hamF4U2V0dGluZ3MudHJhZGl0aW9uYWwpLG4uaXNBcnJheShhKXx8YS5qcXVlcnkmJiFuLmlzUGxhaW5PYmplY3QoYSkpbi5lYWNoKGEsZnVuY3Rpb24oKXtlKHRoaXMubmFtZSx0aGlzLnZhbHVlKX0pO2Vsc2UgZm9yKGMgaW4gYSlHYihjLGFbY10sYixlKTtyZXR1cm4gZC5qb2luKCImIikucmVwbGFjZShCYiwiKyIpfSxuLmZuLmV4dGVuZCh7c2VyaWFsaXplOmZ1bmN0aW9uKCl7cmV0dXJuIG4ucGFyYW0odGhpcy5zZXJpYWxpemVBcnJheSgpKX0sc2VyaWFsaXplQXJyYXk6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5tYXAoZnVuY3Rpb24oKXt2YXIgYT1uLnByb3AodGhpcywiZWxlbWVudHMiKTtyZXR1cm4gYT9uLm1ha2VBcnJheShhKTp0aGlzfSkuZmlsdGVyKGZ1bmN0aW9uKCl7dmFyIGE9dGhpcy50eXBlO3JldHVybiB0aGlzLm5hbWUmJiFuKHRoaXMpLmlzKCI6ZGlzYWJsZWQiKSYmRmIudGVzdCh0aGlzLm5vZGVOYW1lKSYmIUViLnRlc3QoYSkmJih0aGlzLmNoZWNrZWR8fCFYLnRlc3QoYSkpfSkubWFwKGZ1bmN0aW9uKGEsYil7dmFyIGM9bih0aGlzKS52YWwoKTtyZXR1cm4gbnVsbD09Yz9udWxsOm4uaXNBcnJheShjKT9uLm1hcChjLGZ1bmN0aW9uKGEpe3JldHVybntuYW1lOmIubmFtZSx2YWx1ZTphLnJlcGxhY2UoRGIsIlxyXG4iKX19KTp7bmFtZTpiLm5hbWUsdmFsdWU6Yy5yZXBsYWNlKERiLCJcclxuIil9fSkuZ2V0KCl9fSksbi5hamF4U2V0dGluZ3MueGhyPWZ1bmN0aW9uKCl7dHJ5e3JldHVybiBuZXcgYS5YTUxIdHRwUmVxdWVzdH1jYXRjaChiKXt9fTt2YXIgSGI9ezA6MjAwLDEyMjM6MjA0fSxJYj1uLmFqYXhTZXR0aW5ncy54aHIoKTtsLmNvcnM9ISFJYiYmIndpdGhDcmVkZW50aWFscyJpbiBJYixsLmFqYXg9SWI9ISFJYixuLmFqYXhUcmFuc3BvcnQoZnVuY3Rpb24oYil7dmFyIGMsZDtyZXR1cm4gbC5jb3JzfHxJYiYmIWIuY3Jvc3NEb21haW4/e3NlbmQ6ZnVuY3Rpb24oZSxmKXt2YXIgZyxoPWIueGhyKCk7aWYoaC5vcGVuKGIudHlwZSxiLnVybCxiLmFzeW5jLGIudXNlcm5hbWUsYi5wYXNzd29yZCksYi54aHJGaWVsZHMpZm9yKGcgaW4gYi54aHJGaWVsZHMpaFtnXT1iLnhockZpZWxkc1tnXTtiLm1pbWVUeXBlJiZoLm92ZXJyaWRlTWltZVR5cGUmJmgub3ZlcnJpZGVNaW1lVHlwZShiLm1pbWVUeXBlKSxiLmNyb3NzRG9tYWlufHxlWyJYLVJlcXVlc3RlZC1XaXRoIl18fChlWyJYLVJlcXVlc3RlZC1XaXRoIl09IlhNTEh0dHBSZXF1ZXN0Iik7Zm9yKGcgaW4gZSloLnNldFJlcXVlc3RIZWFkZXIoZyxlW2ddKTtjPWZ1bmN0aW9uKGEpe3JldHVybiBmdW5jdGlvbigpe2MmJihjPWQ9aC5vbmxvYWQ9aC5vbmVycm9yPWgub25hYm9ydD1oLm9ucmVhZHlzdGF0ZWNoYW5nZT1udWxsLCJhYm9ydCI9PT1hP2guYWJvcnQoKToiZXJyb3IiPT09YT8ibnVtYmVyIiE9dHlwZW9mIGguc3RhdHVzP2YoMCwiZXJyb3IiKTpmKGguc3RhdHVzLGguc3RhdHVzVGV4dCk6ZihIYltoLnN0YXR1c118fGguc3RhdHVzLGguc3RhdHVzVGV4dCwidGV4dCIhPT0oaC5yZXNwb25zZVR5cGV8fCJ0ZXh0Iil8fCJzdHJpbmciIT10eXBlb2YgaC5yZXNwb25zZVRleHQ/e2JpbmFyeTpoLnJlc3BvbnNlfTp7dGV4dDpoLnJlc3BvbnNlVGV4dH0saC5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSkpfX0saC5vbmxvYWQ9YygpLGQ9aC5vbmVycm9yPWMoImVycm9yIiksdm9pZCAwIT09aC5vbmFib3J0P2gub25hYm9ydD1kOmgub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7ND09PWgucmVhZHlTdGF0ZSYmYS5zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7YyYmZCgpfSl9LGM9YygiYWJvcnQiKTt0cnl7aC5zZW5kKGIuaGFzQ29udGVudCYmYi5kYXRhfHxudWxsKX1jYXRjaChpKXtpZihjKXRocm93IGl9fSxhYm9ydDpmdW5jdGlvbigpe2MmJmMoKX19OnZvaWQgMH0pLG4uYWpheFNldHVwKHthY2NlcHRzOntzY3JpcHQ6InRleHQvamF2YXNjcmlwdCwgYXBwbGljYXRpb24vamF2YXNjcmlwdCwgYXBwbGljYXRpb24vZWNtYXNjcmlwdCwgYXBwbGljYXRpb24veC1lY21hc2NyaXB0In0sY29udGVudHM6e3NjcmlwdDovXGIoPzpqYXZhfGVjbWEpc2NyaXB0XGIvfSxjb252ZXJ0ZXJzOnsidGV4dCBzY3JpcHQiOmZ1bmN0aW9uKGEpe3JldHVybiBuLmdsb2JhbEV2YWwoYSksYX19fSksbi5hamF4UHJlZmlsdGVyKCJzY3JpcHQiLGZ1bmN0aW9uKGEpe3ZvaWQgMD09PWEuY2FjaGUmJihhLmNhY2hlPSExKSxhLmNyb3NzRG9tYWluJiYoYS50eXBlPSJHRVQiKX0pLG4uYWpheFRyYW5zcG9ydCgic2NyaXB0IixmdW5jdGlvbihhKXtpZihhLmNyb3NzRG9tYWluKXt2YXIgYixjO3JldHVybntzZW5kOmZ1bmN0aW9uKGUsZil7Yj1uKCI8c2NyaXB0PiIpLnByb3Aoe2NoYXJzZXQ6YS5zY3JpcHRDaGFyc2V0LHNyYzphLnVybH0pLm9uKCJsb2FkIGVycm9yIixjPWZ1bmN0aW9uKGEpe2IucmVtb3ZlKCksYz1udWxsLGEmJmYoImVycm9yIj09PWEudHlwZT80MDQ6MjAwLGEudHlwZSl9KSxkLmhlYWQuYXBwZW5kQ2hpbGQoYlswXSl9LGFib3J0OmZ1bmN0aW9uKCl7YyYmYygpfX19fSk7dmFyIEpiPVtdLEtiPS8oPSlcPyg/PSZ8JCl8XD9cPy87bi5hamF4U2V0dXAoe2pzb25wOiJjYWxsYmFjayIsanNvbnBDYWxsYmFjazpmdW5jdGlvbigpe3ZhciBhPUpiLnBvcCgpfHxuLmV4cGFuZG8rIl8iK2tiKys7cmV0dXJuIHRoaXNbYV09ITAsYX19KSxuLmFqYXhQcmVmaWx0ZXIoImpzb24ganNvbnAiLGZ1bmN0aW9uKGIsYyxkKXt2YXIgZSxmLGcsaD1iLmpzb25wIT09ITEmJihLYi50ZXN0KGIudXJsKT8idXJsIjoic3RyaW5nIj09dHlwZW9mIGIuZGF0YSYmMD09PShiLmNvbnRlbnRUeXBlfHwiIikuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIikmJktiLnRlc3QoYi5kYXRhKSYmImRhdGEiKTtyZXR1cm4gaHx8Impzb25wIj09PWIuZGF0YVR5cGVzWzBdPyhlPWIuanNvbnBDYWxsYmFjaz1uLmlzRnVuY3Rpb24oYi5qc29ucENhbGxiYWNrKT9iLmpzb25wQ2FsbGJhY2soKTpiLmpzb25wQ2FsbGJhY2ssaD9iW2hdPWJbaF0ucmVwbGFjZShLYiwiJDEiK2UpOmIuanNvbnAhPT0hMSYmKGIudXJsKz0obGIudGVzdChiLnVybCk/IiYiOiI/IikrYi5qc29ucCsiPSIrZSksYi5jb252ZXJ0ZXJzWyJzY3JpcHQganNvbiJdPWZ1bmN0aW9uKCl7cmV0dXJuIGd8fG4uZXJyb3IoZSsiIHdhcyBub3QgY2FsbGVkIiksZ1swXX0sYi5kYXRhVHlwZXNbMF09Impzb24iLGY9YVtlXSxhW2VdPWZ1bmN0aW9uKCl7Zz1hcmd1bWVudHN9LGQuYWx3YXlzKGZ1bmN0aW9uKCl7dm9pZCAwPT09Zj9uKGEpLnJlbW92ZVByb3AoZSk6YVtlXT1mLGJbZV0mJihiLmpzb25wQ2FsbGJhY2s9Yy5qc29ucENhbGxiYWNrLEpiLnB1c2goZSkpLGcmJm4uaXNGdW5jdGlvbihmKSYmZihnWzBdKSxnPWY9dm9pZCAwfSksInNjcmlwdCIpOnZvaWQgMH0pLG4ucGFyc2VIVE1MPWZ1bmN0aW9uKGEsYixjKXtpZighYXx8InN0cmluZyIhPXR5cGVvZiBhKXJldHVybiBudWxsOyJib29sZWFuIj09dHlwZW9mIGImJihjPWIsYj0hMSksYj1ifHxkO3ZhciBlPXguZXhlYyhhKSxmPSFjJiZbXTtyZXR1cm4gZT9bYi5jcmVhdGVFbGVtZW50KGVbMV0pXTooZT1jYShbYV0sYixmKSxmJiZmLmxlbmd0aCYmbihmKS5yZW1vdmUoKSxuLm1lcmdlKFtdLGUuY2hpbGROb2RlcykpfTt2YXIgTGI9bi5mbi5sb2FkO24uZm4ubG9hZD1mdW5jdGlvbihhLGIsYyl7aWYoInN0cmluZyIhPXR5cGVvZiBhJiZMYilyZXR1cm4gTGIuYXBwbHkodGhpcyxhcmd1bWVudHMpO3ZhciBkLGUsZixnPXRoaXMsaD1hLmluZGV4T2YoIiAiKTtyZXR1cm4gaD4tMSYmKGQ9bi50cmltKGEuc2xpY2UoaCkpLGE9YS5zbGljZSgwLGgpKSxuLmlzRnVuY3Rpb24oYik/KGM9YixiPXZvaWQgMCk6YiYmIm9iamVjdCI9PXR5cGVvZiBiJiYoZT0iUE9TVCIpLGcubGVuZ3RoPjAmJm4uYWpheCh7dXJsOmEsdHlwZTplfHwiR0VUIixkYXRhVHlwZToiaHRtbCIsZGF0YTpifSkuZG9uZShmdW5jdGlvbihhKXtmPWFyZ3VtZW50cyxnLmh0bWwoZD9uKCI8ZGl2PiIpLmFwcGVuZChuLnBhcnNlSFRNTChhKSkuZmluZChkKTphKX0pLmFsd2F5cyhjJiZmdW5jdGlvbihhLGIpe2cuZWFjaChmdW5jdGlvbigpe2MuYXBwbHkoZyxmfHxbYS5yZXNwb25zZVRleHQsYixhXSl9KX0pLHRoaXN9LG4uZWFjaChbImFqYXhTdGFydCIsImFqYXhTdG9wIiwiYWpheENvbXBsZXRlIiwiYWpheEVycm9yIiwiYWpheFN1Y2Nlc3MiLCJhamF4U2VuZCJdLGZ1bmN0aW9uKGEsYil7bi5mbltiXT1mdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5vbihiLGEpfX0pLG4uZXhwci5maWx0ZXJzLmFuaW1hdGVkPWZ1bmN0aW9uKGEpe3JldHVybiBuLmdyZXAobi50aW1lcnMsZnVuY3Rpb24oYil7cmV0dXJuIGE9PT1iLmVsZW19KS5sZW5ndGh9O2Z1bmN0aW9uIE1iKGEpe3JldHVybiBuLmlzV2luZG93KGEpP2E6OT09PWEubm9kZVR5cGUmJmEuZGVmYXVsdFZpZXd9bi5vZmZzZXQ9e3NldE9mZnNldDpmdW5jdGlvbihhLGIsYyl7dmFyIGQsZSxmLGcsaCxpLGosaz1uLmNzcyhhLCJwb3NpdGlvbiIpLGw9bihhKSxtPXt9OyJzdGF0aWMiPT09ayYmKGEuc3R5bGUucG9zaXRpb249InJlbGF0aXZlIiksaD1sLm9mZnNldCgpLGY9bi5jc3MoYSwidG9wIiksaT1uLmNzcyhhLCJsZWZ0Iiksaj0oImFic29sdXRlIj09PWt8fCJmaXhlZCI9PT1rKSYmKGYraSkuaW5kZXhPZigiYXV0byIpPi0xLGo/KGQ9bC5wb3NpdGlvbigpLGc9ZC50b3AsZT1kLmxlZnQpOihnPXBhcnNlRmxvYXQoZil8fDAsZT1wYXJzZUZsb2F0KGkpfHwwKSxuLmlzRnVuY3Rpb24oYikmJihiPWIuY2FsbChhLGMsbi5leHRlbmQoe30saCkpKSxudWxsIT1iLnRvcCYmKG0udG9wPWIudG9wLWgudG9wK2cpLG51bGwhPWIubGVmdCYmKG0ubGVmdD1iLmxlZnQtaC5sZWZ0K2UpLCJ1c2luZyJpbiBiP2IudXNpbmcuY2FsbChhLG0pOmwuY3NzKG0pfX0sbi5mbi5leHRlbmQoe29mZnNldDpmdW5jdGlvbihhKXtpZihhcmd1bWVudHMubGVuZ3RoKXJldHVybiB2b2lkIDA9PT1hP3RoaXM6dGhpcy5lYWNoKGZ1bmN0aW9uKGIpe24ub2Zmc2V0LnNldE9mZnNldCh0aGlzLGEsYil9KTt2YXIgYixjLGQ9dGhpc1swXSxlPXt0b3A6MCxsZWZ0OjB9LGY9ZCYmZC5vd25lckRvY3VtZW50O2lmKGYpcmV0dXJuIGI9Zi5kb2N1bWVudEVsZW1lbnQsbi5jb250YWlucyhiLGQpPyhlPWQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksYz1NYihmKSx7dG9wOmUudG9wK2MucGFnZVlPZmZzZXQtYi5jbGllbnRUb3AsbGVmdDplLmxlZnQrYy5wYWdlWE9mZnNldC1iLmNsaWVudExlZnR9KTplfSxwb3NpdGlvbjpmdW5jdGlvbigpe2lmKHRoaXNbMF0pe3ZhciBhLGIsYz10aGlzWzBdLGQ9e3RvcDowLGxlZnQ6MH07cmV0dXJuImZpeGVkIj09PW4uY3NzKGMsInBvc2l0aW9uIik/Yj1jLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOihhPXRoaXMub2Zmc2V0UGFyZW50KCksYj10aGlzLm9mZnNldCgpLG4ubm9kZU5hbWUoYVswXSwiaHRtbCIpfHwoZD1hLm9mZnNldCgpKSxkLnRvcCs9bi5jc3MoYVswXSwiYm9yZGVyVG9wV2lkdGgiLCEwKSxkLmxlZnQrPW4uY3NzKGFbMF0sImJvcmRlckxlZnRXaWR0aCIsITApKSx7dG9wOmIudG9wLWQudG9wLW4uY3NzKGMsIm1hcmdpblRvcCIsITApLGxlZnQ6Yi5sZWZ0LWQubGVmdC1uLmNzcyhjLCJtYXJnaW5MZWZ0IiwhMCl9fX0sb2Zmc2V0UGFyZW50OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubWFwKGZ1bmN0aW9uKCl7dmFyIGE9dGhpcy5vZmZzZXRQYXJlbnQ7d2hpbGUoYSYmInN0YXRpYyI9PT1uLmNzcyhhLCJwb3NpdGlvbiIpKWE9YS5vZmZzZXRQYXJlbnQ7cmV0dXJuIGF8fEVhfSl9fSksbi5lYWNoKHtzY3JvbGxMZWZ0OiJwYWdlWE9mZnNldCIsc2Nyb2xsVG9wOiJwYWdlWU9mZnNldCJ9LGZ1bmN0aW9uKGEsYil7dmFyIGM9InBhZ2VZT2Zmc2V0Ij09PWI7bi5mblthXT1mdW5jdGlvbihkKXtyZXR1cm4gSyh0aGlzLGZ1bmN0aW9uKGEsZCxlKXt2YXIgZj1NYihhKTtyZXR1cm4gdm9pZCAwPT09ZT9mP2ZbYl06YVtkXTp2b2lkKGY/Zi5zY3JvbGxUbyhjP2YucGFnZVhPZmZzZXQ6ZSxjP2U6Zi5wYWdlWU9mZnNldCk6YVtkXT1lKX0sYSxkLGFyZ3VtZW50cy5sZW5ndGgpfX0pLG4uZWFjaChbInRvcCIsImxlZnQiXSxmdW5jdGlvbihhLGIpe24uY3NzSG9va3NbYl09R2EobC5waXhlbFBvc2l0aW9uLGZ1bmN0aW9uKGEsYyl7cmV0dXJuIGM/KGM9RmEoYSxiKSxCYS50ZXN0KGMpP24oYSkucG9zaXRpb24oKVtiXSsicHgiOmMpOnZvaWQgMH0pfSksbi5lYWNoKHtIZWlnaHQ6ImhlaWdodCIsV2lkdGg6IndpZHRoIn0sZnVuY3Rpb24oYSxiKXtuLmVhY2goe3BhZGRpbmc6ImlubmVyIithLGNvbnRlbnQ6YiwiIjoib3V0ZXIiK2F9LGZ1bmN0aW9uKGMsZCl7bi5mbltkXT1mdW5jdGlvbihkLGUpe3ZhciBmPWFyZ3VtZW50cy5sZW5ndGgmJihjfHwiYm9vbGVhbiIhPXR5cGVvZiBkKSxnPWN8fChkPT09ITB8fGU9PT0hMD8ibWFyZ2luIjoiYm9yZGVyIik7cmV0dXJuIEsodGhpcyxmdW5jdGlvbihiLGMsZCl7dmFyIGU7cmV0dXJuIG4uaXNXaW5kb3coYik/Yi5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnRbImNsaWVudCIrYV06OT09PWIubm9kZVR5cGU/KGU9Yi5kb2N1bWVudEVsZW1lbnQsTWF0aC5tYXgoYi5ib2R5WyJzY3JvbGwiK2FdLGVbInNjcm9sbCIrYV0sYi5ib2R5WyJvZmZzZXQiK2FdLGVbIm9mZnNldCIrYV0sZVsiY2xpZW50IithXSkpOnZvaWQgMD09PWQ/bi5jc3MoYixjLGcpOm4uc3R5bGUoYixjLGQsZyl9LGIsZj9kOnZvaWQgMCxmLG51bGwpfX0pfSksbi5mbi5leHRlbmQoe2JpbmQ6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiB0aGlzLm9uKGEsbnVsbCxiLGMpfSx1bmJpbmQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5vZmYoYSxudWxsLGIpfSxkZWxlZ2F0ZTpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gdGhpcy5vbihiLGEsYyxkKX0sdW5kZWxlZ2F0ZTpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIDE9PT1hcmd1bWVudHMubGVuZ3RoP3RoaXMub2ZmKGEsIioqIik6dGhpcy5vZmYoYixhfHwiKioiLGMpfSxzaXplOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMubGVuZ3RofX0pLG4uZm4uYW5kU2VsZj1uLmZuLmFkZEJhY2ssImZ1bmN0aW9uIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZCYmZGVmaW5lKCJqcXVlcnkiLFtdLGZ1bmN0aW9uKCl7cmV0dXJuIG59KTt2YXIgTmI9YS5qUXVlcnksT2I9YS4kO3JldHVybiBuLm5vQ29uZmxpY3Q9ZnVuY3Rpb24oYil7cmV0dXJuIGEuJD09PW4mJihhLiQ9T2IpLGImJmEualF1ZXJ5PT09biYmKGEualF1ZXJ5PU5iKSxufSxifHwoYS5qUXVlcnk9YS4kPW4pLG59KTsNCg=="></script>
  <style>
/*

Twilight style from Rick Strahl <http: weblog.west-wind.com/="">
based on dark.css by Vladimir Epifanov 

*/

.hljs {
  display: block;
  overflow-x: auto;
  padding: 0.5em;
  background: #252525;
  color: #E2E2E2;
  font-weight: normal;  
  font-size: 1.15em !important;  
}

.hljs-keyword,
.hljs-selector-tag,
.hljs-built_in,
.hljs-tag {
  color: #CDA869;
}

.hljs-template-tag {
  color: #dcdcdc;
}

.hljs-number {
  color: #CF6A4C;
}

.hljs-attr {
  color: cornsilk;
}

.hljs-variable,
.hljs-template-variable
{
  color: #efdcbc;
}

.hljs-literal {
  color: #CF6A4C;
}

.hljs-subst {
  color: #8f8f8f;
}

.hljs-title {  
  color: #C78C3B;
}


.hljs-name,
.hljs-selector-id,
.hljs-selector-class,
.hljs-section,
.hljs-type {  
  color:#d5ad69;
}

.hljs-symbol,
.hljs-bullet,
.hljs-link {
  color: #dca3a3;
}

.hljs-string {
   color: #8F9D6A;
}

.hljs-deletion,
.hljs-builtin-name {
  color: #cc9393;
}

.hljs-comment {
   font-style: italic;
   color: #888;
}

.hljs-addition,
.hljs-quote,
.hljs-meta {
  color: #7f9f7f;
}


.hljs-emphasis {
  font-style: italic;
}

.hljs-strong {
  font-weight: bold;
}

</http:></style>
  <script src="data:text/javascript;base64,LyohIGhpZ2hsaWdodC5qcyB2OS4xNS4xMCB8IEJTRDMgTGljZW5zZSB8IGdpdC5pby9obGpzbGljZW5zZSAqLwohZnVuY3Rpb24oZSl7dmFyIHQ9Im9iamVjdCI9PXR5cGVvZiB3aW5kb3cmJndpbmRvd3x8Im9iamVjdCI9PXR5cGVvZiBzZWxmJiZzZWxmOyJ1bmRlZmluZWQiPT10eXBlb2YgZXhwb3J0c3x8ZXhwb3J0cy5ub2RlVHlwZT90JiYodC5obGpzPWUoe30pLCJmdW5jdGlvbiI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQmJmRlZmluZShbXSxmdW5jdGlvbigpe3JldHVybiB0LmhsanN9KSk6ZShleHBvcnRzKX0oZnVuY3Rpb24obyl7dmFyIEU9W10sYz1PYmplY3Qua2V5cyxTPXt9LHU9e30sdD0vXihuby0/aGlnaGxpZ2h0KSQvaSxfPS9cYmxhbmcoPzp1YWdlKT8tKFtcdy1dKylcYi9pLHI9LygoXig8W14+XSs+fFx0fCkrfCg/OlxuKSkpL2dtLGE9e2Nhc2VfaW5zZW5zaXRpdmU6ImNJIixsZXhlbWVzOiJsIixjb250YWluczoiYyIsa2V5d29yZHM6ImsiLHN1Ykxhbmd1YWdlOiJzTCIsY2xhc3NOYW1lOiJjTiIsYmVnaW46ImIiLGJlZ2luS2V5d29yZHM6ImJLIixlbmQ6ImUiLGVuZHNXaXRoUGFyZW50OiJlVyIsaWxsZWdhbDoiaSIsZXhjbHVkZUJlZ2luOiJlQiIsZXhjbHVkZUVuZDoiZUUiLHJldHVybkJlZ2luOiJyQiIscmV0dXJuRW5kOiJyRSIscmVsZXZhbmNlOiJyIix2YXJpYW50czoidiIsSURFTlRfUkU6IklSIixVTkRFUlNDT1JFX0lERU5UX1JFOiJVSVIiLE5VTUJFUl9SRToiTlIiLENfTlVNQkVSX1JFOiJDTlIiLEJJTkFSWV9OVU1CRVJfUkU6IkJOUiIsUkVfU1RBUlRFUlNfUkU6IlJTUiIsQkFDS1NMQVNIX0VTQ0FQRToiQkUiLEFQT1NfU1RSSU5HX01PREU6IkFTTSIsUVVPVEVfU1RSSU5HX01PREU6IlFTTSIsUEhSQVNBTF9XT1JEU19NT0RFOiJQV00iLENfTElORV9DT01NRU5UX01PREU6IkNMQ00iLENfQkxPQ0tfQ09NTUVOVF9NT0RFOiJDQkNNIixIQVNIX0NPTU1FTlRfTU9ERToiSENNIixOVU1CRVJfTU9ERToiTk0iLENfTlVNQkVSX01PREU6IkNOTSIsQklOQVJZX05VTUJFUl9NT0RFOiJCTk0iLENTU19OVU1CRVJfTU9ERToiQ1NTTk0iLFJFR0VYUF9NT0RFOiJSTSIsVElUTEVfTU9ERToiVE0iLFVOREVSU0NPUkVfVElUTEVfTU9ERToiVVRNIixDT01NRU5UOiJDIixiZWdpblJlOiJiUiIsZW5kUmU6ImVSIixpbGxlZ2FsUmU6ImlSIixsZXhlbWVzUmU6ImxSIix0ZXJtaW5hdG9yczoidCIsdGVybWluYXRvcl9lbmQ6InRFIn0sYj0iPC9zcGFuPiIsQT17Y2xhc3NQcmVmaXg6ImhsanMtIix0YWJSZXBsYWNlOm51bGwsdXNlQlI6ITEsbGFuZ3VhZ2VzOnZvaWQgMH07ZnVuY3Rpb24gVChlKXtyZXR1cm4gZS5yZXBsYWNlKC8mL2csIiZhbXA7IikucmVwbGFjZSgvPC9nLCImbHQ7IikucmVwbGFjZSgvPi9nLCImZ3Q7Iil9ZnVuY3Rpb24gcChlKXtyZXR1cm4gZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpfWZ1bmN0aW9uIEkoZSx0KXt2YXIgcj1lJiZlLmV4ZWModCk7cmV0dXJuIHImJjA9PT1yLmluZGV4fWZ1bmN0aW9uIFIoZSl7cmV0dXJuIHQudGVzdChlKX1mdW5jdGlvbiBOKGUpe3ZhciB0LHI9e30sYT1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSk7Zm9yKHQgaW4gZSlyW3RdPWVbdF07cmV0dXJuIGEuZm9yRWFjaChmdW5jdGlvbihlKXtmb3IodCBpbiBlKXJbdF09ZVt0XX0pLHJ9ZnVuY3Rpb24gbShlKXt2YXIgbz1bXTtyZXR1cm4gZnVuY3Rpb24gZSh0LHIpe2Zvcih2YXIgYT10LmZpcnN0Q2hpbGQ7YTthPWEubmV4dFNpYmxpbmcpMz09PWEubm9kZVR5cGU/cis9YS5ub2RlVmFsdWUubGVuZ3RoOjE9PT1hLm5vZGVUeXBlJiYoby5wdXNoKHtldmVudDoic3RhcnQiLG9mZnNldDpyLG5vZGU6YX0pLHI9ZShhLHIpLHAoYSkubWF0Y2goL2JyfGhyfGltZ3xpbnB1dC8pfHxvLnB1c2goe2V2ZW50OiJzdG9wIixvZmZzZXQ6cixub2RlOmF9KSk7cmV0dXJuIHJ9KGUsMCksb31mdW5jdGlvbiBpKGUpe2lmKGEmJiFlLmxhbmdBcGlSZXN0b3JlZCl7Zm9yKHZhciB0IGluIGUubGFuZ0FwaVJlc3RvcmVkPSEwLGEpZVt0XSYmKGVbYVt0XV09ZVt0XSk7KGUuY3x8W10pLmNvbmNhdChlLnZ8fFtdKS5mb3JFYWNoKGkpfX1mdW5jdGlvbiBDKG4pe2Z1bmN0aW9uIGwoZSl7cmV0dXJuIGUmJmUuc291cmNlfHxlfWZ1bmN0aW9uIHMoZSx0KXtyZXR1cm4gbmV3IFJlZ0V4cChsKGUpLCJtIisobi5jST8iaSI6IiIpKyh0PyJnIjoiIikpfSFmdW5jdGlvbiB0KHIsZSl7aWYoIXIuY29tcGlsZWQpe2lmKHIuY29tcGlsZWQ9ITAsci5rPXIua3x8ci5iSyxyLmspe3ZhciBhPXt9LG89ZnVuY3Rpb24ocixlKXtuLmNJJiYoZT1lLnRvTG93ZXJDYXNlKCkpLGUuc3BsaXQoIiAiKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWUuc3BsaXQoInwiKTthW3RbMF1dPVtyLHRbMV0/TnVtYmVyKHRbMV0pOjFdfSl9OyJzdHJpbmciPT10eXBlb2Ygci5rP28oImtleXdvcmQiLHIuayk6YyhyLmspLmZvckVhY2goZnVuY3Rpb24oZSl7byhlLHIua1tlXSl9KSxyLms9YX1yLmxSPXMoci5sfHwvXHcrLywhMCksZSYmKHIuYksmJihyLmI9IlxcYigiK3IuYksuc3BsaXQoIiAiKS5qb2luKCJ8IikrIilcXGIiKSxyLmJ8fChyLmI9L1xCfFxiLyksci5iUj1zKHIuYiksci5lbmRTYW1lQXNCZWdpbiYmKHIuZT1yLmIpLHIuZXx8ci5lV3x8KHIuZT0vXEJ8XGIvKSxyLmUmJihyLmVSPXMoci5lKSksci50RT1sKHIuZSl8fCIiLHIuZVcmJmUudEUmJihyLnRFKz0oci5lPyJ8IjoiIikrZS50RSkpLHIuaSYmKHIuaVI9cyhyLmkpKSxudWxsPT1yLnImJihyLnI9MSksci5jfHwoci5jPVtdKSxyLmM9QXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxyLmMubWFwKGZ1bmN0aW9uKGUpe3JldHVybih0PSJzZWxmIj09PWU/cjplKS52JiYhdC5jYWNoZWRfdmFyaWFudHMmJih0LmNhY2hlZF92YXJpYW50cz10LnYubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBOKHQse3Y6bnVsbH0sZSl9KSksdC5jYWNoZWRfdmFyaWFudHN8fHQuZVcmJltOKHQpXXx8W3RdO3ZhciB0fSkpLHIuYy5mb3JFYWNoKGZ1bmN0aW9uKGUpe3QoZSxyKX0pLHIuc3RhcnRzJiZ0KHIuc3RhcnRzLGUpO3ZhciBpPXIuYy5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUuYks/IlxcLj8oPzoiK2UuYisiKVxcLj8iOmUuYn0pLmNvbmNhdChbci50RSxyLmldKS5tYXAobCkuZmlsdGVyKEJvb2xlYW4pO3IudD1pLmxlbmd0aD9zKGZ1bmN0aW9uKGUsdCl7Zm9yKHZhciByPS9cWyg/OlteXFxcXV18XFwuKSpcXXxcKFw/P3xcXChbMS05XVswLTldKil8XFwuLyxhPTAsbz0iIixpPTA7aTxlLmxlbmd0aDtpKyspe3ZhciBuPWEscz1sKGVbaV0pO2ZvcigwPGkmJihvKz10KTswPHMubGVuZ3RoOyl7dmFyIGM9ci5leGVjKHMpO2lmKG51bGw9PWMpe28rPXM7YnJlYWt9bys9cy5zdWJzdHJpbmcoMCxjLmluZGV4KSxzPXMuc3Vic3RyaW5nKGMuaW5kZXgrY1swXS5sZW5ndGgpLCJcXCI9PWNbMF1bMF0mJmNbMV0/bys9IlxcIitTdHJpbmcoTnVtYmVyKGNbMV0pK24pOihvKz1jWzBdLCIoIj09Y1swXSYmYSsrKX19cmV0dXJuIG99KGksInwiKSwhMCk6e2V4ZWM6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbH19fX0obil9ZnVuY3Rpb24gZyhlLHQscyxyKXtmdW5jdGlvbiBjKGUsdCxyLGEpe3ZhciBvPSc8c3BhbiBjbGFzcz0iJysoYT8iIjpBLmNsYXNzUHJlZml4KTtyZXR1cm4gZT8obys9ZSsnIj4nKSt0KyhyPyIiOmIpOnR9ZnVuY3Rpb24gbCgpe3UrPW51bGwhPUUuc0w/ZnVuY3Rpb24oKXt2YXIgZT0ic3RyaW5nIj09dHlwZW9mIEUuc0w7aWYoZSYmIVNbRS5zTF0pcmV0dXJuIFQoXyk7dmFyIHQ9ZT9nKEUuc0wsXywhMCxpW0Uuc0xdKTpmKF8sRS5zTC5sZW5ndGg/RS5zTDp2b2lkIDApO3JldHVybiAwPEUuciYmKHArPXQuciksZSYmKGlbRS5zTF09dC50b3ApLGModC5sYW5ndWFnZSx0LnZhbHVlLCExLCEwKX0oKTpmdW5jdGlvbigpe3ZhciBlLHQscixhLG8saSxuO2lmKCFFLmspcmV0dXJuIFQoXyk7Zm9yKGE9IiIsdD0wLEUubFIubGFzdEluZGV4PTAscj1FLmxSLmV4ZWMoXyk7cjspYSs9VChfLnN1YnN0cmluZyh0LHIuaW5kZXgpKSxvPUUsaT1yLG49ZC5jST9pWzBdLnRvTG93ZXJDYXNlKCk6aVswXSwoZT1vLmsuaGFzT3duUHJvcGVydHkobikmJm8ua1tuXSk/KHArPWVbMV0sYSs9YyhlWzBdLFQoclswXSkpKTphKz1UKHJbMF0pLHQ9RS5sUi5sYXN0SW5kZXgscj1FLmxSLmV4ZWMoXyk7cmV0dXJuIGErVChfLnN1YnN0cih0KSl9KCksXz0iIn1mdW5jdGlvbiBOKGUpe3UrPWUuY04/YyhlLmNOLCIiLCEwKToiIixFPU9iamVjdC5jcmVhdGUoZSx7cGFyZW50Ont2YWx1ZTpFfX0pfWZ1bmN0aW9uIGEoZSx0KXtpZihfKz1lLG51bGw9PXQpcmV0dXJuIGwoKSwwO3ZhciByPWZ1bmN0aW9uKGUsdCl7dmFyIHIsYSxvO2ZvcihyPTAsYT10LmMubGVuZ3RoO3I8YTtyKyspaWYoSSh0LmNbcl0uYlIsZSkpcmV0dXJuIHQuY1tyXS5lbmRTYW1lQXNCZWdpbiYmKHQuY1tyXS5lUj0obz10LmNbcl0uYlIuZXhlYyhlKVswXSxuZXcgUmVnRXhwKG8ucmVwbGFjZSgvWy1cL1xcXiQqKz8uKCl8W1xde31dL2csIlxcJCYiKSwibSIpKSksdC5jW3JdfSh0LEUpO2lmKHIpcmV0dXJuIHIuc2tpcD9fKz10OihyLmVCJiYoXys9dCksbCgpLHIuckJ8fHIuZUJ8fChfPXQpKSxOKHIpLHIuckI/MDp0Lmxlbmd0aDt2YXIgYSxvLGk9ZnVuY3Rpb24gZSh0LHIpe2lmKEkodC5lUixyKSl7Zm9yKDt0LmVuZHNQYXJlbnQmJnQucGFyZW50Oyl0PXQucGFyZW50O3JldHVybiB0fWlmKHQuZVcpcmV0dXJuIGUodC5wYXJlbnQscil9KEUsdCk7aWYoaSl7dmFyIG49RTtmb3Iobi5za2lwP18rPXQ6KG4uckV8fG4uZUV8fChfKz10KSxsKCksbi5lRSYmKF89dCkpO0UuY04mJih1Kz1iKSxFLnNraXB8fEUuc0x8fChwKz1FLnIpLChFPUUucGFyZW50KSE9PWkucGFyZW50Oyk7cmV0dXJuIGkuc3RhcnRzJiYoaS5lbmRTYW1lQXNCZWdpbiYmKGkuc3RhcnRzLmVSPWkuZVIpLE4oaS5zdGFydHMpKSxuLnJFPzA6dC5sZW5ndGh9aWYoYT10LG89RSwhcyYmSShvLmlSLGEpKXRocm93IG5ldyBFcnJvcignSWxsZWdhbCBsZXhlbWUgIicrdCsnIiBmb3IgbW9kZSAiJysoRS5jTnx8Ijx1bm5hbWVkPiIpKyciJyk7cmV0dXJuIF8rPXQsdC5sZW5ndGh8fDF9dmFyIGQ9TyhlKTtpZighZCl0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gbGFuZ3VhZ2U6ICInK2UrJyInKTtDKGQpO3ZhciBvLEU9cnx8ZCxpPXt9LHU9IiI7Zm9yKG89RTtvIT09ZDtvPW8ucGFyZW50KW8uY04mJih1PWMoby5jTiwiIiwhMCkrdSk7dmFyIF89IiIscD0wO3RyeXtmb3IodmFyIG4sUixtPTA7RS50Lmxhc3RJbmRleD1tLG49RS50LmV4ZWModCk7KVI9YSh0LnN1YnN0cmluZyhtLG4uaW5kZXgpLG5bMF0pLG09bi5pbmRleCtSO2ZvcihhKHQuc3Vic3RyKG0pKSxvPUU7by5wYXJlbnQ7bz1vLnBhcmVudClvLmNOJiYodSs9Yik7cmV0dXJue3I6cCx2YWx1ZTp1LGxhbmd1YWdlOmUsdG9wOkV9fWNhdGNoKGUpe2lmKGUubWVzc2FnZSYmLTEhPT1lLm1lc3NhZ2UuaW5kZXhPZigiSWxsZWdhbCIpKXJldHVybntyOjAsdmFsdWU6VCh0KX07dGhyb3cgZX19ZnVuY3Rpb24gZihyLGUpe2U9ZXx8QS5sYW5ndWFnZXN8fGMoUyk7dmFyIGE9e3I6MCx2YWx1ZTpUKHIpfSxvPWE7cmV0dXJuIGUuZmlsdGVyKE8pLmZpbHRlcihsKS5mb3JFYWNoKGZ1bmN0aW9uKGUpe3ZhciB0PWcoZSxyLCExKTt0Lmxhbmd1YWdlPWUsdC5yPm8uciYmKG89dCksdC5yPmEuciYmKG89YSxhPXQpfSksby5sYW5ndWFnZSYmKGEuc2Vjb25kX2Jlc3Q9byksYX1mdW5jdGlvbiB2KGUpe3JldHVybiBBLnRhYlJlcGxhY2V8fEEudXNlQlI/ZS5yZXBsYWNlKHIsZnVuY3Rpb24oZSx0KXtyZXR1cm4gQS51c2VCUiYmIlxuIj09PWU/Ijxicj4iOkEudGFiUmVwbGFjZT90LnJlcGxhY2UoL1x0L2csQS50YWJSZXBsYWNlKToiIn0pOmV9ZnVuY3Rpb24gbihlKXt2YXIgdCxyLGEsbyxpLG4scyxjLGwsTixkPWZ1bmN0aW9uKGUpe3ZhciB0LHIsYSxvLGk9ZS5jbGFzc05hbWUrIiAiO2lmKGkrPWUucGFyZW50Tm9kZT9lLnBhcmVudE5vZGUuY2xhc3NOYW1lOiIiLHI9Xy5leGVjKGkpKXJldHVybiBPKHJbMV0pP3JbMV06Im5vLWhpZ2hsaWdodCI7Zm9yKHQ9MCxhPShpPWkuc3BsaXQoL1xzKy8pKS5sZW5ndGg7dDxhO3QrKylpZihSKG89aVt0XSl8fE8obykpcmV0dXJuIG99KGUpO1IoZCl8fChBLnVzZUJSPyh0PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUygiaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIsImRpdiIpKS5pbm5lckhUTUw9ZS5pbm5lckhUTUwucmVwbGFjZSgvXG4vZywiIikucmVwbGFjZSgvPGJyWyBcL10qPi9nLCJcbiIpOnQ9ZSxpPXQudGV4dENvbnRlbnQsYT1kP2coZCxpLCEwKTpmKGkpLChyPW0odCkpLmxlbmd0aCYmKChvPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUygiaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIsImRpdiIpKS5pbm5lckhUTUw9YS52YWx1ZSxhLnZhbHVlPWZ1bmN0aW9uKGUsdCxyKXt2YXIgYT0wLG89IiIsaT1bXTtmdW5jdGlvbiBuKCl7cmV0dXJuIGUubGVuZ3RoJiZ0Lmxlbmd0aD9lWzBdLm9mZnNldCE9PXRbMF0ub2Zmc2V0P2VbMF0ub2Zmc2V0PHRbMF0ub2Zmc2V0P2U6dDoic3RhcnQiPT09dFswXS5ldmVudD9lOnQ6ZS5sZW5ndGg/ZTp0fWZ1bmN0aW9uIHMoZSl7bys9IjwiK3AoZSkrRS5tYXAuY2FsbChlLmF0dHJpYnV0ZXMsZnVuY3Rpb24oZSl7cmV0dXJuIiAiK2Uubm9kZU5hbWUrJz0iJytUKGUudmFsdWUpLnJlcGxhY2UoJyInLCImcXVvdDsiKSsnIid9KS5qb2luKCIiKSsiPiJ9ZnVuY3Rpb24gYyhlKXtvKz0iPC8iK3AoZSkrIj4ifWZ1bmN0aW9uIGwoZSl7KCJzdGFydCI9PT1lLmV2ZW50P3M6YykoZS5ub2RlKX1mb3IoO2UubGVuZ3RofHx0Lmxlbmd0aDspe3ZhciBOPW4oKTtpZihvKz1UKHIuc3Vic3RyaW5nKGEsTlswXS5vZmZzZXQpKSxhPU5bMF0ub2Zmc2V0LE49PT1lKXtmb3IoaS5yZXZlcnNlKCkuZm9yRWFjaChjKTtsKE4uc3BsaWNlKDAsMSlbMF0pLChOPW4oKSk9PT1lJiZOLmxlbmd0aCYmTlswXS5vZmZzZXQ9PT1hOyk7aS5yZXZlcnNlKCkuZm9yRWFjaChzKX1lbHNlInN0YXJ0Ij09PU5bMF0uZXZlbnQ/aS5wdXNoKE5bMF0ubm9kZSk6aS5wb3AoKSxsKE4uc3BsaWNlKDAsMSlbMF0pfXJldHVybiBvK1Qoci5zdWJzdHIoYSkpfShyLG0obyksaSkpLGEudmFsdWU9dihhLnZhbHVlKSxlLmlubmVySFRNTD1hLnZhbHVlLGUuY2xhc3NOYW1lPShuPWUuY2xhc3NOYW1lLHM9ZCxjPWEubGFuZ3VhZ2UsbD1zP3Vbc106YyxOPVtuLnRyaW0oKV0sbi5tYXRjaCgvXGJobGpzXGIvKXx8Ti5wdXNoKCJobGpzIiksLTE9PT1uLmluZGV4T2YobCkmJk4ucHVzaChsKSxOLmpvaW4oIiAiKS50cmltKCkpLGUucmVzdWx0PXtsYW5ndWFnZTphLmxhbmd1YWdlLHJlOmEucn0sYS5zZWNvbmRfYmVzdCYmKGUuc2Vjb25kX2Jlc3Q9e2xhbmd1YWdlOmEuc2Vjb25kX2Jlc3QubGFuZ3VhZ2UscmU6YS5zZWNvbmRfYmVzdC5yfSkpfWZ1bmN0aW9uIHMoKXtpZighcy5jYWxsZWQpe3MuY2FsbGVkPSEwO3ZhciBlPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoInByZSBjb2RlIik7RS5mb3JFYWNoLmNhbGwoZSxuKX19ZnVuY3Rpb24gTyhlKXtyZXR1cm4gZT0oZXx8IiIpLnRvTG93ZXJDYXNlKCksU1tlXXx8U1t1W2VdXX1mdW5jdGlvbiBsKGUpe3ZhciB0PU8oZSk7cmV0dXJuIHQmJiF0LmRpc2FibGVBdXRvZGV0ZWN0fXJldHVybiBvLmhpZ2hsaWdodD1nLG8uaGlnaGxpZ2h0QXV0bz1mLG8uZml4TWFya3VwPXYsby5oaWdobGlnaHRCbG9jaz1uLG8uY29uZmlndXJlPWZ1bmN0aW9uKGUpe0E9TihBLGUpfSxvLmluaXRIaWdobGlnaHRpbmc9cyxvLmluaXRIaWdobGlnaHRpbmdPbkxvYWQ9ZnVuY3Rpb24oKXthZGRFdmVudExpc3RlbmVyKCJET01Db250ZW50TG9hZGVkIixzLCExKSxhZGRFdmVudExpc3RlbmVyKCJsb2FkIixzLCExKX0sby5yZWdpc3Rlckxhbmd1YWdlPWZ1bmN0aW9uKHQsZSl7dmFyIHI9U1t0XT1lKG8pO2kociksci5hbGlhc2VzJiZyLmFsaWFzZXMuZm9yRWFjaChmdW5jdGlvbihlKXt1W2VdPXR9KX0sby5saXN0TGFuZ3VhZ2VzPWZ1bmN0aW9uKCl7cmV0dXJuIGMoUyl9LG8uZ2V0TGFuZ3VhZ2U9TyxvLmF1dG9EZXRlY3Rpb249bCxvLmluaGVyaXQ9TixvLklSPW8uSURFTlRfUkU9IlthLXpBLVpdXFx3KiIsby5VSVI9by5VTkRFUlNDT1JFX0lERU5UX1JFPSJbYS16QS1aX11cXHcqIixvLk5SPW8uTlVNQkVSX1JFPSJcXGJcXGQrKFxcLlxcZCspPyIsby5DTlI9by5DX05VTUJFUl9SRT0iKC0/KShcXGIwW3hYXVthLWZBLUYwLTldK3woXFxiXFxkKyhcXC5cXGQqKT98XFwuXFxkKykoW2VFXVstK10/XFxkKyk/KSIsby5CTlI9by5CSU5BUllfTlVNQkVSX1JFPSJcXGIoMGJbMDFdKykiLG8uUlNSPW8uUkVfU1RBUlRFUlNfUkU9IiF8IT18IT09fCV8JT18JnwmJnwmPXxcXCp8XFwqPXxcXCt8XFwrPXwsfC18LT18Lz18L3w6fDt8PDx8PDw9fDw9fDx8PT09fD09fD18Pj4+PXw+Pj18Pj18Pj4+fD4+fD58XFw/fFxcW3xcXHt8XFwofFxcXnxcXF49fFxcfHxcXHw9fFxcfFxcfHx+IixvLkJFPW8uQkFDS1NMQVNIX0VTQ0FQRT17YjoiXFxcXFtcXHNcXFNdIixyOjB9LG8uQVNNPW8uQVBPU19TVFJJTkdfTU9ERT17Y046InN0cmluZyIsYjoiJyIsZToiJyIsaToiXFxuIixjOltvLkJFXX0sby5RU009by5RVU9URV9TVFJJTkdfTU9ERT17Y046InN0cmluZyIsYjonIicsZTonIicsaToiXFxuIixjOltvLkJFXX0sby5QV009by5QSFJBU0FMX1dPUkRTX01PREU9e2I6L1xiKGF8YW58dGhlfGFyZXxJJ218aXNuJ3R8ZG9uJ3R8ZG9lc24ndHx3b24ndHxidXR8anVzdHxzaG91bGR8cHJldHR5fHNpbXBseXxlbm91Z2h8Z29ubmF8Z29pbmd8d3RmfHNvfHN1Y2h8d2lsbHx5b3V8eW91cnx0aGV5fGxpa2V8bW9yZSlcYi99LG8uQz1vLkNPTU1FTlQ9ZnVuY3Rpb24oZSx0LHIpe3ZhciBhPW8uaW5oZXJpdCh7Y046ImNvbW1lbnQiLGI6ZSxlOnQsYzpbXX0scnx8e30pO3JldHVybiBhLmMucHVzaChvLlBXTSksYS5jLnB1c2goe2NOOiJkb2N0YWciLGI6Iig/OlRPRE98RklYTUV8Tk9URXxCVUd8WFhYKToiLHI6MH0pLGF9LG8uQ0xDTT1vLkNfTElORV9DT01NRU5UX01PREU9by5DKCIvLyIsIiQiKSxvLkNCQ009by5DX0JMT0NLX0NPTU1FTlRfTU9ERT1vLkMoIi9cXCoiLCJcXCovIiksby5IQ009by5IQVNIX0NPTU1FTlRfTU9ERT1vLkMoIiMiLCIkIiksby5OTT1vLk5VTUJFUl9NT0RFPXtjTjoibnVtYmVyIixiOm8uTlIscjowfSxvLkNOTT1vLkNfTlVNQkVSX01PREU9e2NOOiJudW1iZXIiLGI6by5DTlIscjowfSxvLkJOTT1vLkJJTkFSWV9OVU1CRVJfTU9ERT17Y046Im51bWJlciIsYjpvLkJOUixyOjB9LG8uQ1NTTk09by5DU1NfTlVNQkVSX01PREU9e2NOOiJudW1iZXIiLGI6by5OUisiKCV8ZW18ZXh8Y2h8cmVtfHZ3fHZofHZtaW58dm1heHxjbXxtbXxpbnxwdHxwY3xweHxkZWd8Z3JhZHxyYWR8dHVybnxzfG1zfEh6fGtIenxkcGl8ZHBjbXxkcHB4KT8iLHI6MH0sby5STT1vLlJFR0VYUF9NT0RFPXtjTjoicmVnZXhwIixiOi9cLy8sZTovXC9bZ2ltdXldKi8saTovXG4vLGM6W28uQkUse2I6L1xbLyxlOi9cXS8scjowLGM6W28uQkVdfV19LG8uVE09by5USVRMRV9NT0RFPXtjTjoidGl0bGUiLGI6by5JUixyOjB9LG8uVVRNPW8uVU5ERVJTQ09SRV9USVRMRV9NT0RFPXtjTjoidGl0bGUiLGI6by5VSVIscjowfSxvLk1FVEhPRF9HVUFSRD17YjoiXFwuXFxzKiIrby5VSVIscjowfSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImFwYWNoZSIsZnVuY3Rpb24oZSl7dmFyIHQ9e2NOOiJudW1iZXIiLGI6IltcXCQlXVxcZCsifTtyZXR1cm57YWxpYXNlczpbImFwYWNoZWNvbmYiXSxjSTohMCxjOltlLkhDTSx7Y046InNlY3Rpb24iLGI6IjwvPyIsZToiPiJ9LHtjTjoiYXR0cmlidXRlIixiOi9cdysvLHI6MCxrOntub21hcmt1cDoib3JkZXIgZGVueSBhbGxvdyBzZXRlbnYgcmV3cml0ZXJ1bGUgcmV3cml0ZWVuZ2luZSByZXdyaXRlY29uZCBkb2N1bWVudHJvb3Qgc2V0aGFuZGxlciBlcnJvcmRvY3VtZW50IGxvYWRtb2R1bGUgb3B0aW9ucyBoZWFkZXIgbGlzdGVuIHNlcnZlcnJvb3Qgc2VydmVybmFtZSJ9LHN0YXJ0czp7ZTovJC8scjowLGs6e2xpdGVyYWw6Im9uIG9mZiBhbGwifSxjOlt7Y046Im1ldGEiLGI6Ilxcc1xcWyIsZToiXFxdJCJ9LHtjTjoidmFyaWFibGUiLGI6IltcXCQlXVxceyIsZToiXFx9IixjOlsic2VsZiIsdF19LHQsZS5RU01dfX1dLGk6L1xTL319KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImJhc2giLGZ1bmN0aW9uKGUpe3ZhciB0PXtjTjoidmFyaWFibGUiLHY6W3tiOi9cJFtcd1xkI0BdW1x3XGRfXSovfSx7YjovXCRceyguKj8pfS99XX0scj17Y046InN0cmluZyIsYjovIi8sZTovIi8sYzpbZS5CRSx0LHtjTjoidmFyaWFibGUiLGI6L1wkXCgvLGU6L1wpLyxjOltlLkJFXX1dfTtyZXR1cm57YWxpYXNlczpbInNoIiwienNoIl0sbDovXGItP1thLXpcLl9dK1xiLyxrOntrZXl3b3JkOiJpZiB0aGVuIGVsc2UgZWxpZiBmaSBmb3Igd2hpbGUgaW4gZG8gZG9uZSBjYXNlIGVzYWMgZnVuY3Rpb24iLGxpdGVyYWw6InRydWUgZmFsc2UiLGJ1aWx0X2luOiJicmVhayBjZCBjb250aW51ZSBldmFsIGV4ZWMgZXhpdCBleHBvcnQgZ2V0b3B0cyBoYXNoIHB3ZCByZWFkb25seSByZXR1cm4gc2hpZnQgdGVzdCB0aW1lcyB0cmFwIHVtYXNrIHVuc2V0IGFsaWFzIGJpbmQgYnVpbHRpbiBjYWxsZXIgY29tbWFuZCBkZWNsYXJlIGVjaG8gZW5hYmxlIGhlbHAgbGV0IGxvY2FsIGxvZ291dCBtYXBmaWxlIHByaW50ZiByZWFkIHJlYWRhcnJheSBzb3VyY2UgdHlwZSB0eXBlc2V0IHVsaW1pdCB1bmFsaWFzIHNldCBzaG9wdCBhdXRvbG9hZCBiZyBiaW5ka2V5IGJ5ZSBjYXAgY2hkaXIgY2xvbmUgY29tcGFyZ3VtZW50cyBjb21wY2FsbCBjb21wY3RsIGNvbXBkZXNjcmliZSBjb21wZmlsZXMgY29tcGdyb3VwcyBjb21wcXVvdGUgY29tcHRhZ3MgY29tcHRyeSBjb21wdmFsdWVzIGRpcnMgZGlzYWJsZSBkaXNvd24gZWNob3RjIGVjaG90aSBlbXVsYXRlIGZjIGZnIGZsb2F0IGZ1bmN0aW9ucyBnZXRjYXAgZ2V0bG4gaGlzdG9yeSBpbnRlZ2VyIGpvYnMga2lsbCBsaW1pdCBsb2cgbm9nbG9iIHBvcGQgcHJpbnQgcHVzaGQgcHVzaGxuIHJlaGFzaCBzY2hlZCBzZXRjYXAgc2V0b3B0IHN0YXQgc3VzcGVuZCB0dHljdGwgdW5mdW5jdGlvbiB1bmhhc2ggdW5saW1pdCB1bnNldG9wdCB2YXJlZCB3YWl0IHdoZW5jZSB3aGVyZSB3aGljaCB6Y29tcGlsZSB6Zm9ybWF0IHpmdHAgemxlIHptb2Rsb2FkIHpwYXJzZW9wdHMgenByb2YgenB0eSB6cmVnZXhwYXJzZSB6c29ja2V0IHpzdHlsZSB6dGNwIixfOiItbmUgLWVxIC1sdCAtZ3QgLWYgLWQgLWUgLXMgLWwgLWEifSxjOlt7Y046Im1ldGEiLGI6L14jIVteXG5dK3NoXHMqJC8scjoxMH0se2NOOiJmdW5jdGlvbiIsYjovXHdbXHdcZF9dKlxzKlwoXHMqXClccypcey8sckI6ITAsYzpbZS5pbmhlcml0KGUuVE0se2I6L1x3W1x3XGRfXSovfSldLHI6MH0sZS5IQ00scix7Y046IiIsYjovXFwiL30se2NOOiJzdHJpbmciLGI6LycvLGU6LycvfSx0XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImNwcCIsZnVuY3Rpb24oZSl7dmFyIHQ9e2NOOiJrZXl3b3JkIixiOiJcXGJbYS16XFxkX10qX3RcXGIifSxyPXtjTjoic3RyaW5nIix2Olt7YjonKHU4P3xVfEwpPyInLGU6JyInLGk6IlxcbiIsYzpbZS5CRV19LHtiOi8oPzp1OD98VXxMKT9SIihbXigpXFwgXXswLDE2fSlcKCg/Oi58XG4pKj9cKVwxIi99LHtiOiInXFxcXD8uIixlOiInIixpOiIuIn1dfSxhPXtjTjoibnVtYmVyIix2Olt7YjoiXFxiKDBiWzAxJ10rKSJ9LHtiOiIoLT8pXFxiKFtcXGQnXSsoXFwuW1xcZCddKik/fFxcLltcXGQnXSspKHV8VXxsfEx8dWx8VUx8ZnxGfGJ8QikifSx7YjoiKC0/KShcXGIwW3hYXVthLWZBLUYwLTknXSt8KFxcYltcXGQnXSsoXFwuW1xcZCddKik/fFxcLltcXGQnXSspKFtlRV1bLStdP1tcXGQnXSspPykifV0scjowfSxvPXtjTjoibWV0YSIsYjovI1xzKlthLXpdK1xiLyxlOi8kLyxrOnsibWV0YS1rZXl3b3JkIjoiaWYgZWxzZSBlbGlmIGVuZGlmIGRlZmluZSB1bmRlZiB3YXJuaW5nIGVycm9yIGxpbmUgcHJhZ21hIGlmZGVmIGlmbmRlZiBpbmNsdWRlIn0sYzpbe2I6L1xcXG4vLHI6MH0sZS5pbmhlcml0KHIse2NOOiJtZXRhLXN0cmluZyJ9KSx7Y046Im1ldGEtc3RyaW5nIixiOi88W15cbj5dKj4vLGU6LyQvLGk6IlxcbiJ9LGUuQ0xDTSxlLkNCQ01dfSxpPWUuSVIrIlxccypcXCgiLG49e2tleXdvcmQ6ImludCBmbG9hdCB3aGlsZSBwcml2YXRlIGNoYXIgY2F0Y2ggaW1wb3J0IG1vZHVsZSBleHBvcnQgdmlydHVhbCBvcGVyYXRvciBzaXplb2YgZHluYW1pY19jYXN0fDEwIHR5cGVkZWYgY29uc3RfY2FzdHwxMCBjb25zdCBmb3Igc3RhdGljX2Nhc3R8MTAgdW5pb24gbmFtZXNwYWNlIHVuc2lnbmVkIGxvbmcgdm9sYXRpbGUgc3RhdGljIHByb3RlY3RlZCBib29sIHRlbXBsYXRlIG11dGFibGUgaWYgcHVibGljIGZyaWVuZCBkbyBnb3RvIGF1dG8gdm9pZCBlbnVtIGVsc2UgYnJlYWsgZXh0ZXJuIHVzaW5nIGFzbSBjYXNlIHR5cGVpZCBzaG9ydCByZWludGVycHJldF9jYXN0fDEwIGRlZmF1bHQgZG91YmxlIHJlZ2lzdGVyIGV4cGxpY2l0IHNpZ25lZCB0eXBlbmFtZSB0cnkgdGhpcyBzd2l0Y2ggY29udGludWUgaW5saW5lIGRlbGV0ZSBhbGlnbm9mIGNvbnN0ZXhwciBkZWNsdHlwZSBub2V4Y2VwdCBzdGF0aWNfYXNzZXJ0IHRocmVhZF9sb2NhbCByZXN0cmljdCBfQm9vbCBjb21wbGV4IF9Db21wbGV4IF9JbWFnaW5hcnkgYXRvbWljX2Jvb2wgYXRvbWljX2NoYXIgYXRvbWljX3NjaGFyIGF0b21pY191Y2hhciBhdG9taWNfc2hvcnQgYXRvbWljX3VzaG9ydCBhdG9taWNfaW50IGF0b21pY191aW50IGF0b21pY19sb25nIGF0b21pY191bG9uZyBhdG9taWNfbGxvbmcgYXRvbWljX3VsbG9uZyBuZXcgdGhyb3cgcmV0dXJuIGFuZCBvciBub3QiLGJ1aWx0X2luOiJzdGQgc3RyaW5nIGNpbiBjb3V0IGNlcnIgY2xvZyBzdGRpbiBzdGRvdXQgc3RkZXJyIHN0cmluZ3N0cmVhbSBpc3RyaW5nc3RyZWFtIG9zdHJpbmdzdHJlYW0gYXV0b19wdHIgZGVxdWUgbGlzdCBxdWV1ZSBzdGFjayB2ZWN0b3IgbWFwIHNldCBiaXRzZXQgbXVsdGlzZXQgbXVsdGltYXAgdW5vcmRlcmVkX3NldCB1bm9yZGVyZWRfbWFwIHVub3JkZXJlZF9tdWx0aXNldCB1bm9yZGVyZWRfbXVsdGltYXAgYXJyYXkgc2hhcmVkX3B0ciBhYm9ydCBhYnMgYWNvcyBhc2luIGF0YW4yIGF0YW4gY2FsbG9jIGNlaWwgY29zaCBjb3MgZXhpdCBleHAgZmFicyBmbG9vciBmbW9kIGZwcmludGYgZnB1dHMgZnJlZSBmcmV4cCBmc2NhbmYgaXNhbG51bSBpc2FscGhhIGlzY250cmwgaXNkaWdpdCBpc2dyYXBoIGlzbG93ZXIgaXNwcmludCBpc3B1bmN0IGlzc3BhY2UgaXN1cHBlciBpc3hkaWdpdCB0b2xvd2VyIHRvdXBwZXIgbGFicyBsZGV4cCBsb2cxMCBsb2cgbWFsbG9jIHJlYWxsb2MgbWVtY2hyIG1lbWNtcCBtZW1jcHkgbWVtc2V0IG1vZGYgcG93IHByaW50ZiBwdXRjaGFyIHB1dHMgc2NhbmYgc2luaCBzaW4gc25wcmludGYgc3ByaW50ZiBzcXJ0IHNzY2FuZiBzdHJjYXQgc3RyY2hyIHN0cmNtcCBzdHJjcHkgc3RyY3NwbiBzdHJsZW4gc3RybmNhdCBzdHJuY21wIHN0cm5jcHkgc3RycGJyayBzdHJyY2hyIHN0cnNwbiBzdHJzdHIgdGFuaCB0YW4gdmZwcmludGYgdnByaW50ZiB2c3ByaW50ZiBlbmRsIGluaXRpYWxpemVyX2xpc3QgdW5pcXVlX3B0ciIsbGl0ZXJhbDoidHJ1ZSBmYWxzZSBudWxscHRyIE5VTEwifSxzPVt0LGUuQ0xDTSxlLkNCQ00sYSxyXTtyZXR1cm57YWxpYXNlczpbImMiLCJjYyIsImgiLCJjKysiLCJoKysiLCJocHAiLCJoaCIsImh4eCIsImN4eCJdLGs6bixpOiI8LyIsYzpzLmNvbmNhdChbbyx7YjoiXFxiKGRlcXVlfGxpc3R8cXVldWV8c3RhY2t8dmVjdG9yfG1hcHxzZXR8Yml0c2V0fG11bHRpc2V0fG11bHRpbWFwfHVub3JkZXJlZF9tYXB8dW5vcmRlcmVkX3NldHx1bm9yZGVyZWRfbXVsdGlzZXR8dW5vcmRlcmVkX211bHRpbWFwfGFycmF5KVxccyo8IixlOiI+IixrOm4sYzpbInNlbGYiLHRdfSx7YjplLklSKyI6OiIsazpufSx7djpbe2I6Lz0vLGU6LzsvfSx7YjovXCgvLGU6L1wpL30se2JLOiJuZXcgdGhyb3cgcmV0dXJuIGVsc2UiLGU6LzsvfV0sazpuLGM6cy5jb25jYXQoW3tiOi9cKC8sZTovXCkvLGs6bixjOnMuY29uY2F0KFsic2VsZiJdKSxyOjB9XSkscjowfSx7Y046ImZ1bmN0aW9uIixiOiIoIitlLklSKyJbXFwqJlxcc10rKSsiK2ksckI6ITAsZTovW3s7PV0vLGVFOiEwLGs6bixpOi9bXlx3XHNcKiZdLyxjOlt7YjppLHJCOiEwLGM6W2UuVE1dLHI6MH0se2NOOiJwYXJhbXMiLGI6L1woLyxlOi9cKS8sazpuLHI6MCxjOltlLkNMQ00sZS5DQkNNLHIsYSx0LHtiOi9cKC8sZTovXCkvLGs6bixyOjAsYzpbInNlbGYiLGUuQ0xDTSxlLkNCQ00scixhLHRdfV19LGUuQ0xDTSxlLkNCQ00sb119LHtjTjoiY2xhc3MiLGJLOiJjbGFzcyBzdHJ1Y3QiLGU6L1t7OzpdLyxjOlt7YjovPC8sZTovPi8sYzpbInNlbGYiXX0sZS5UTV19XSksZXhwb3J0czp7cHJlcHJvY2Vzc29yOm8sc3RyaW5nczpyLGs6bn19fSksby5yZWdpc3Rlckxhbmd1YWdlKCJjcyIsZnVuY3Rpb24oZSl7dmFyIHQ9e2tleXdvcmQ6ImFic3RyYWN0IGFzIGJhc2UgYm9vbCBicmVhayBieXRlIGNhc2UgY2F0Y2ggY2hhciBjaGVja2VkIGNvbnN0IGNvbnRpbnVlIGRlY2ltYWwgZGVmYXVsdCBkZWxlZ2F0ZSBkbyBkb3VibGUgZW51bSBldmVudCBleHBsaWNpdCBleHRlcm4gZmluYWxseSBmaXhlZCBmbG9hdCBmb3IgZm9yZWFjaCBnb3RvIGlmIGltcGxpY2l0IGluIGludCBpbnRlcmZhY2UgaW50ZXJuYWwgaXMgbG9jayBsb25nIG9iamVjdCBvcGVyYXRvciBvdXQgb3ZlcnJpZGUgcGFyYW1zIHByaXZhdGUgcHJvdGVjdGVkIHB1YmxpYyByZWFkb25seSByZWYgc2J5dGUgc2VhbGVkIHNob3J0IHNpemVvZiBzdGFja2FsbG9jIHN0YXRpYyBzdHJpbmcgc3RydWN0IHN3aXRjaCB0aGlzIHRyeSB0eXBlb2YgdWludCB1bG9uZyB1bmNoZWNrZWQgdW5zYWZlIHVzaG9ydCB1c2luZyB2aXJ0dWFsIHZvaWQgdm9sYXRpbGUgd2hpbGUgYWRkIGFsaWFzIGFzY2VuZGluZyBhc3luYyBhd2FpdCBieSBkZXNjZW5kaW5nIGR5bmFtaWMgZXF1YWxzIGZyb20gZ2V0IGdsb2JhbCBncm91cCBpbnRvIGpvaW4gbGV0IG5hbWVvZiBvbiBvcmRlcmJ5IHBhcnRpYWwgcmVtb3ZlIHNlbGVjdCBzZXQgdmFsdWUgdmFyIHdoZW4gd2hlcmUgeWllbGQiLGxpdGVyYWw6Im51bGwgZmFsc2UgdHJ1ZSJ9LHI9e2NOOiJudW1iZXIiLHY6W3tiOiJcXGIoMGJbMDEnXSspIn0se2I6IigtPylcXGIoW1xcZCddKyhcXC5bXFxkJ10qKT98XFwuW1xcZCddKykodXxVfGx8THx1bHxVTHxmfEZ8YnxCKSJ9LHtiOiIoLT8pKFxcYjBbeFhdW2EtZkEtRjAtOSddK3woXFxiW1xcZCddKyhcXC5bXFxkJ10qKT98XFwuW1xcZCddKykoW2VFXVstK10/W1xcZCddKyk/KSJ9XSxyOjB9LGE9e2NOOiJzdHJpbmciLGI6J0AiJyxlOiciJyxjOlt7YjonIiInfV19LG89ZS5pbmhlcml0KGEse2k6L1xuL30pLGk9e2NOOiJzdWJzdCIsYjoieyIsZToifSIsazp0fSxuPWUuaW5oZXJpdChpLHtpOi9cbi99KSxzPXtjTjoic3RyaW5nIixiOi9cJCIvLGU6JyInLGk6L1xuLyxjOlt7Yjoie3sifSx7YjoifX0ifSxlLkJFLG5dfSxjPXtjTjoic3RyaW5nIixiOi9cJEAiLyxlOiciJyxjOlt7Yjoie3sifSx7YjoifX0ifSx7YjonIiInfSxpXX0sbD1lLmluaGVyaXQoYyx7aTovXG4vLGM6W3tiOiJ7eyJ9LHtiOiJ9fSJ9LHtiOiciIid9LG5dfSk7aS5jPVtjLHMsYSxlLkFTTSxlLlFTTSxyLGUuQ0JDTV0sbi5jPVtsLHMsbyxlLkFTTSxlLlFTTSxyLGUuaW5oZXJpdChlLkNCQ00se2k6L1xuL30pXTt2YXIgTj17djpbYyxzLGEsZS5BU00sZS5RU01dfSxkPWUuSVIrIig8IitlLklSKyIoXFxzKixcXHMqIitlLklSKyIpKj4pPyhcXFtcXF0pPyI7cmV0dXJue2FsaWFzZXM6WyJjc2hhcnAiLCJjIyJdLGs6dCxpOi86Oi8sYzpbZS5DKCIvLy8iLCIkIix7ckI6ITAsYzpbe2NOOiJkb2N0YWciLHY6W3tiOiIvLy8iLHI6MH0se2I6Ilx4M2MhLS18LS1ceDNlIn0se2I6IjwvPyIsZToiPiJ9XX1dfSksZS5DTENNLGUuQ0JDTSx7Y046Im1ldGEiLGI6IiMiLGU6IiQiLGs6eyJtZXRhLWtleXdvcmQiOiJpZiBlbHNlIGVsaWYgZW5kaWYgZGVmaW5lIHVuZGVmIHdhcm5pbmcgZXJyb3IgbGluZSByZWdpb24gZW5kcmVnaW9uIHByYWdtYSBjaGVja3N1bSJ9fSxOLHIse2JLOiJjbGFzcyBpbnRlcmZhY2UiLGU6L1t7Oz1dLyxpOi9bXlxzOixdLyxjOltlLlRNLGUuQ0xDTSxlLkNCQ01dfSx7Yks6Im5hbWVzcGFjZSIsZTovW3s7PV0vLGk6L1teXHM6XS8sYzpbZS5pbmhlcml0KGUuVE0se2I6IlthLXpBLVpdKFxcLj9cXHcpKiJ9KSxlLkNMQ00sZS5DQkNNXX0se2NOOiJtZXRhIixiOiJeXFxzKlxcWyIsZUI6ITAsZToiXFxdIixlRTohMCxjOlt7Y046Im1ldGEtc3RyaW5nIixiOi8iLyxlOi8iL31dfSx7Yks6Im5ldyByZXR1cm4gdGhyb3cgYXdhaXQgZWxzZSIscjowfSx7Y046ImZ1bmN0aW9uIixiOiIoIitkKyJcXHMrKSsiK2UuSVIrIlxccypcXCgiLHJCOiEwLGU6L1xzKlt7Oz1dLyxlRTohMCxrOnQsYzpbe2I6ZS5JUisiXFxzKlxcKCIsckI6ITAsYzpbZS5UTV0scjowfSx7Y046InBhcmFtcyIsYjovXCgvLGU6L1wpLyxlQjohMCxlRTohMCxrOnQscjowLGM6W04scixlLkNCQ01dfSxlLkNMQ00sZS5DQkNNXX1dfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgiY3NzIixmdW5jdGlvbihlKXt2YXIgdD17YjovKD86W0EtWlxfXC5cLV0rfC0tW2EtekEtWjAtOV8tXSspXHMqOi8sckI6ITAsZToiOyIsZVc6ITAsYzpbe2NOOiJhdHRyaWJ1dGUiLGI6L1xTLyxlOiI6IixlRTohMCxzdGFydHM6e2VXOiEwLGVFOiEwLGM6W3tiOi9bXHctXStcKC8sckI6ITAsYzpbe2NOOiJidWlsdF9pbiIsYjovW1x3LV0rL30se2I6L1woLyxlOi9cKS8sYzpbZS5BU00sZS5RU01dfV19LGUuQ1NTTk0sZS5RU00sZS5BU00sZS5DQkNNLHtjTjoibnVtYmVyIixiOiIjWzAtOUEtRmEtZl0rIn0se2NOOiJtZXRhIixiOiIhaW1wb3J0YW50In1dfX1dfTtyZXR1cm57Y0k6ITAsaTovWz1cL3wnXCRdLyxjOltlLkNCQ00se2NOOiJzZWxlY3Rvci1pZCIsYjovI1tBLVphLXowLTlfLV0rL30se2NOOiJzZWxlY3Rvci1jbGFzcyIsYjovXC5bQS1aYS16MC05Xy1dKy99LHtjTjoic2VsZWN0b3ItYXR0ciIsYjovXFsvLGU6L1xdLyxpOiIkIn0se2NOOiJzZWxlY3Rvci1wc2V1ZG8iLGI6LzooOik/W2EtekEtWjAtOVxfXC1cK1woXCkiJy5dKy99LHtiOiJAKGZvbnQtZmFjZXxwYWdlKSIsbDoiW2Etei1dKyIsazoiZm9udC1mYWNlIHBhZ2UifSx7YjoiQCIsZToiW3s7XSIsaTovOi8sYzpbe2NOOiJrZXl3b3JkIixiOi9cdysvfSx7YjovXHMvLGVXOiEwLGVFOiEwLHI6MCxjOltlLkFTTSxlLlFTTSxlLkNTU05NXX1dfSx7Y046InNlbGVjdG9yLXRhZyIsYjoiW2EtekEtWi1dW2EtekEtWjAtOV8tXSoiLHI6MH0se2I6InsiLGU6In0iLGk6L1xTLyxjOltlLkNCQ00sdF19XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoIm1hcmtkb3duIixmdW5jdGlvbihlKXtyZXR1cm57YWxpYXNlczpbIm1kIiwibWtkb3duIiwibWtkIl0sYzpbe2NOOiJzZWN0aW9uIix2Olt7YjoiXiN7MSw2fSIsZToiJCJ9LHtiOiJeLis/XFxuWz0tXXsyLH0kIn1dfSx7YjoiPCIsZToiPiIsc0w6InhtbCIscjowfSx7Y046ImJ1bGxldCIsYjoiXlxccyooWyorLV18KFxcZCtcXC4pKVxccysifSx7Y046InN0cm9uZyIsYjoiWypfXXsyfS4rP1sqX117Mn0ifSx7Y046ImVtcGhhc2lzIix2Olt7YjoiXFwqLis/XFwqIn0se2I6Il8uKz9fIixyOjB9XX0se2NOOiJxdW90ZSIsYjoiXj5cXHMrIixlOiIkIn0se2NOOiJjb2RlIix2Olt7YjoiXmBgYHcqcyokIixlOiJeYGBgcyokIn0se2I6ImAuKz9gIn0se2I6Il4oIHs0fXxcdCkiLGU6IiQiLHI6MH1dfSx7YjoiXlstXFwqXXszLH0iLGU6IiQifSx7YjoiXFxbLis/XFxdW1xcKFxcW10uKj9bXFwpXFxdXSIsckI6ITAsYzpbe2NOOiJzdHJpbmciLGI6IlxcWyIsZToiXFxdIixlQjohMCxyRTohMCxyOjB9LHtjTjoibGluayIsYjoiXFxdXFwoIixlOiJcXCkiLGVCOiEwLGVFOiEwfSx7Y046InN5bWJvbCIsYjoiXFxdXFxbIixlOiJcXF0iLGVCOiEwLGVFOiEwfV0scjoxMH0se2I6L15cW1teXG5dK1xdOi8sckI6ITAsYzpbe2NOOiJzeW1ib2wiLGI6L1xbLyxlOi9cXS8sZUI6ITAsZUU6ITB9LHtjTjoibGluayIsYjovOlxzKi8sZTovJC8sZUI6ITB9XX1dfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgiZGFydCIsZnVuY3Rpb24oZSl7dmFyIHQ9e2NOOiJzdWJzdCIsdjpbe2I6IlxcJFtBLVphLXowLTlfXSsifV19LHI9e2NOOiJzdWJzdCIsdjpbe2I6IlxcJHsiLGU6In0ifV0sazoidHJ1ZSBmYWxzZSBudWxsIHRoaXMgaXMgbmV3IHN1cGVyIn0sYT17Y046InN0cmluZyIsdjpbe2I6InInJyciLGU6IicnJyJ9LHtiOidyIiIiJyxlOiciIiInfSx7YjoiciciLGU6IiciLGk6IlxcbiJ9LHtiOidyIicsZTonIicsaToiXFxuIn0se2I6IicnJyIsZToiJycnIixjOltlLkJFLHQscl19LHtiOiciIiInLGU6JyIiIicsYzpbZS5CRSx0LHJdfSx7YjoiJyIsZToiJyIsaToiXFxuIixjOltlLkJFLHQscl19LHtiOiciJyxlOiciJyxpOiJcXG4iLGM6W2UuQkUsdCxyXX1dfTtyLmM9W2UuQ05NLGFdO3JldHVybntrOntrZXl3b3JkOiJhc3NlcnQgYXN5bmMgYXdhaXQgYnJlYWsgY2FzZSBjYXRjaCBjbGFzcyBjb25zdCBjb250aW51ZSBkZWZhdWx0IGRvIGVsc2UgZW51bSBleHRlbmRzIGZhbHNlIGZpbmFsIGZpbmFsbHkgZm9yIGlmIGluIGlzIG5ldyBudWxsIHJldGhyb3cgcmV0dXJuIHN1cGVyIHN3aXRjaCBzeW5jIHRoaXMgdGhyb3cgdHJ1ZSB0cnkgdmFyIHZvaWQgd2hpbGUgd2l0aCB5aWVsZCBhYnN0cmFjdCBhcyBkeW5hbWljIGV4cG9ydCBleHRlcm5hbCBmYWN0b3J5IGdldCBpbXBsZW1lbnRzIGltcG9ydCBsaWJyYXJ5IG9wZXJhdG9yIHBhcnQgc2V0IHN0YXRpYyB0eXBlZGVmIixidWlsdF9pbjoicHJpbnQgQ29tcGFyYWJsZSBEYXRlVGltZSBEdXJhdGlvbiBGdW5jdGlvbiBJdGVyYWJsZSBJdGVyYXRvciBMaXN0IE1hcCBNYXRjaCBOdWxsIE9iamVjdCBQYXR0ZXJuIFJlZ0V4cCBTZXQgU3RvcHdhdGNoIFN0cmluZyBTdHJpbmdCdWZmZXIgU3RyaW5nU2luayBTeW1ib2wgVHlwZSBVcmkgYm9vbCBkb3VibGUgaW50IG51bSBkb2N1bWVudCB3aW5kb3cgcXVlcnlTZWxlY3RvciBxdWVyeVNlbGVjdG9yQWxsIEVsZW1lbnQgRWxlbWVudExpc3QifSxjOlthLGUuQygiL1xcKlxcKiIsIlxcKi8iLHtzTDoibWFya2Rvd24ifSksZS5DKCIvLy8iLCIkIix7c0w6Im1hcmtkb3duIn0pLGUuQ0xDTSxlLkNCQ00se2NOOiJjbGFzcyIsYks6ImNsYXNzIGludGVyZmFjZSIsZToieyIsZUU6ITAsYzpbe2JLOiJleHRlbmRzIGltcGxlbWVudHMifSxlLlVUTV19LGUuQ05NLHtjTjoibWV0YSIsYjoiQFtBLVphLXpdKyJ9LHtiOiI9PiJ9XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImRpZmYiLGZ1bmN0aW9uKGUpe3JldHVybnthbGlhc2VzOlsicGF0Y2giXSxjOlt7Y046Im1ldGEiLHI6MTAsdjpbe2I6L15AQCArXC1cZCssXGQrICtcK1xkKyxcZCsgK0BAJC99LHtiOi9eXCpcKlwqICtcZCssXGQrICtcKlwqXCpcKiQvfSx7YjovXlwtXC1cLSArXGQrLFxkKyArXC1cLVwtXC0kL31dfSx7Y046ImNvbW1lbnQiLHY6W3tiOi9JbmRleDogLyxlOi8kL30se2I6Lz17Myx9LyxlOi8kL30se2I6L15cLXszfS8sZTovJC99LHtiOi9eXCp7M30gLyxlOi8kL30se2I6L15cK3szfS8sZTovJC99LHtiOi9cKns1fS8sZTovXCp7NX0kL31dfSx7Y046ImFkZGl0aW9uIixiOiJeXFwrIixlOiIkIn0se2NOOiJkZWxldGlvbiIsYjoiXlxcLSIsZToiJCJ9LHtjTjoiYWRkaXRpb24iLGI6Il5cXCEiLGU6IiQifV19fSksby5yZWdpc3Rlckxhbmd1YWdlKCJkbnMiLGZ1bmN0aW9uKGUpe3JldHVybnthbGlhc2VzOlsiYmluZCIsInpvbmUiXSxrOntrZXl3b3JkOiJJTiBBIEFBQUEgQUZTREIgQVBMIENBQSBDRE5TS0VZIENEUyBDRVJUIENOQU1FIERIQ0lEIERMViBETkFNRSBETlNLRVkgRFMgSElQIElQU0VDS0VZIEtFWSBLWCBMT0MgTVggTkFQVFIgTlMgTlNFQyBOU0VDMyBOU0VDM1BBUkFNIFBUUiBSUlNJRyBSUCBTSUcgU09BIFNSViBTU0hGUCBUQSBUS0VZIFRMU0EgVFNJRyBUWFQifSxjOltlLkMoIjsiLCIkIix7cjowfSkse2NOOiJtZXRhIixiOi9eXCQoVFRMfEdFTkVSQVRFfElOQ0xVREV8T1JJR0lOKVxiL30se2NOOiJudW1iZXIiLGI6IigoKFswLTlBLUZhLWZdezEsNH06KXs3fShbMC05QS1GYS1mXXsxLDR9fDopKXwoKFswLTlBLUZhLWZdezEsNH06KXs2fSg6WzAtOUEtRmEtZl17MSw0fXwoKDI1WzAtNV18MlswLTRdXFxkfDFcXGRcXGR8WzEtOV0/XFxkKShcXC4oMjVbMC01XXwyWzAtNF1cXGR8MVxcZFxcZHxbMS05XT9cXGQpKXszfSl8OikpfCgoWzAtOUEtRmEtZl17MSw0fTopezV9KCgoOlswLTlBLUZhLWZdezEsNH0pezEsMn0pfDooKDI1WzAtNV18MlswLTRdXFxkfDFcXGRcXGR8WzEtOV0/XFxkKShcXC4oMjVbMC01XXwyWzAtNF1cXGR8MVxcZFxcZHxbMS05XT9cXGQpKXszfSl8OikpfCgoWzAtOUEtRmEtZl17MSw0fTopezR9KCgoOlswLTlBLUZhLWZdezEsNH0pezEsM30pfCgoOlswLTlBLUZhLWZdezEsNH0pPzooKDI1WzAtNV18MlswLTRdXFxkfDFcXGRcXGR8WzEtOV0/XFxkKShcXC4oMjVbMC01XXwyWzAtNF1cXGR8MVxcZFxcZHxbMS05XT9cXGQpKXszfSkpfDopKXwoKFswLTlBLUZhLWZdezEsNH06KXszfSgoKDpbMC05QS1GYS1mXXsxLDR9KXsxLDR9KXwoKDpbMC05QS1GYS1mXXsxLDR9KXswLDJ9OigoMjVbMC01XXwyWzAtNF1cXGR8MVxcZFxcZHxbMS05XT9cXGQpKFxcLigyNVswLTVdfDJbMC00XVxcZHwxXFxkXFxkfFsxLTldP1xcZCkpezN9KSl8OikpfCgoWzAtOUEtRmEtZl17MSw0fTopezJ9KCgoOlswLTlBLUZhLWZdezEsNH0pezEsNX0pfCgoOlswLTlBLUZhLWZdezEsNH0pezAsM306KCgyNVswLTVdfDJbMC00XVxcZHwxXFxkXFxkfFsxLTldP1xcZCkoXFwuKDI1WzAtNV18MlswLTRdXFxkfDFcXGRcXGR8WzEtOV0/XFxkKSl7M30pKXw6KSl8KChbMC05QS1GYS1mXXsxLDR9Oil7MX0oKCg6WzAtOUEtRmEtZl17MSw0fSl7MSw2fSl8KCg6WzAtOUEtRmEtZl17MSw0fSl7MCw0fTooKDI1WzAtNV18MlswLTRdXFxkfDFcXGRcXGR8WzEtOV0/XFxkKShcXC4oMjVbMC01XXwyWzAtNF1cXGR8MVxcZFxcZHxbMS05XT9cXGQpKXszfSkpfDopKXwoOigoKDpbMC05QS1GYS1mXXsxLDR9KXsxLDd9KXwoKDpbMC05QS1GYS1mXXsxLDR9KXswLDV9OigoMjVbMC01XXwyWzAtNF1cXGR8MVxcZFxcZHxbMS05XT9cXGQpKFxcLigyNVswLTVdfDJbMC00XVxcZHwxXFxkXFxkfFsxLTldP1xcZCkpezN9KSl8OikpKVxcYiJ9LHtjTjoibnVtYmVyIixiOiIoKDI1WzAtNV18KDJbMC00XXwxezAsMX1bMC05XSl7MCwxfVswLTldKS4pezMsM30oMjVbMC01XXwoMlswLTRdfDF7MCwxfVswLTldKXswLDF9WzAtOV0pXFxiIn0sZS5pbmhlcml0KGUuTk0se2I6L1xiXGQrW2Rod21dPy99KV19fSksby5yZWdpc3Rlckxhbmd1YWdlKCJkb2NrZXJmaWxlIixmdW5jdGlvbihlKXtyZXR1cm57YWxpYXNlczpbImRvY2tlciJdLGNJOiEwLGs6ImZyb20gbWFpbnRhaW5lciBleHBvc2UgZW52IGFyZyB1c2VyIG9uYnVpbGQgc3RvcHNpZ25hbCIsYzpbZS5IQ00sZS5BU00sZS5RU00sZS5OTSx7Yks6InJ1biBjbWQgZW50cnlwb2ludCB2b2x1bWUgYWRkIGNvcHkgd29ya2RpciBsYWJlbCBoZWFsdGhjaGVjayBzaGVsbCIsc3RhcnRzOntlOi9bXlxcXSQvLHNMOiJiYXNoIn19XSxpOiI8LyJ9fSksby5yZWdpc3Rlckxhbmd1YWdlKCJkb3MiLGZ1bmN0aW9uKGUpe3ZhciB0PWUuQygvXlxzKkA/cmVtXGIvLC8kLyx7cjoxMH0pO3JldHVybnthbGlhc2VzOlsiYmF0IiwiY21kIl0sY0k6ITAsaTovXC9cKi8sazp7a2V5d29yZDoiaWYgZWxzZSBnb3RvIGZvciBpbiBkbyBjYWxsIGV4aXQgbm90IGV4aXN0IGVycm9ybGV2ZWwgZGVmaW5lZCBlcXUgbmVxIGxzcyBsZXEgZ3RyIGdlcSIsYnVpbHRfaW46InBybiBudWwgbHB0MyBscHQyIGxwdDEgY29uIGNvbTQgY29tMyBjb20yIGNvbTEgYXV4IHNoaWZ0IGNkIGRpciBlY2hvIHNldGxvY2FsIGVuZGxvY2FsIHNldCBwYXVzZSBjb3B5IGFwcGVuZCBhc3NvYyBhdCBhdHRyaWIgYnJlYWsgY2FjbHMgY2QgY2hjcCBjaGRpciBjaGtkc2sgY2hrbnRmcyBjbHMgY21kIGNvbG9yIGNvbXAgY29tcGFjdCBjb252ZXJ0IGRhdGUgZGlyIGRpc2tjb21wIGRpc2tjb3B5IGRvc2tleSBlcmFzZSBmcyBmaW5kIGZpbmRzdHIgZm9ybWF0IGZ0eXBlIGdyYWZ0YWJsIGhlbHAga2V5YiBsYWJlbCBtZCBta2RpciBtb2RlIG1vcmUgbW92ZSBwYXRoIHBhdXNlIHByaW50IHBvcGQgcHVzaGQgcHJvbXQgcmQgcmVjb3ZlciByZW0gcmVuYW1lIHJlcGxhY2UgcmVzdG9yZSBybWRpciBzaGlmdHNvcnQgc3RhcnQgc3Vic3QgdGltZSB0aXRsZSB0cmVlIHR5cGUgdmVyIHZlcmlmeSB2b2wgcGluZyBuZXQgaXBjb25maWcgdGFza2tpbGwgeGNvcHkgcmVuIGRlbCJ9LGM6W3tjTjoidmFyaWFibGUiLGI6LyUlW14gXXwlW14gXSs/JXwhW14gXSs/IS99LHtjTjoiZnVuY3Rpb24iLGI6Il5cXHMqW0EtWmEtei5fP11bQS1aYS16MC05XyQjQH4uP10qKDp8XFxzK2xhYmVsKSIsZToiZ290bzplb2YiLGM6W2UuaW5oZXJpdChlLlRNLHtiOiIoW19hLXpBLVpdXFx3KlxcLikqKFtfYS16QS1aXVxcdyo6KT9bX2EtekEtWl1cXHcqIn0pLHRdfSx7Y046Im51bWJlciIsYjoiXFxiXFxkKyIscjowfSx0XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImZveHBybyIsZnVuY3Rpb24oZSl7cmV0dXJue2FsaWFzZXM6WyJmb3hwcm8iLCJ2ZnAiLCJmb3giXSxjSTohMCxrOntrZXl3b3JkOiJhZGRpdGl2ZSBieSBjYXNlIGNhdGNoIGN1cnNvciBjdXN0b20gZGVjbGFyZSBkZWZpbmUgZG8gZWxzZSBlbmRjYXNlIGVuZGRlZmluZSBlbmRkbyBlbmRmb3IgZW5kZnVuYyBlbmRpZiBlbmRwcmludGpvYiBlbmRwcm9jIGVuZHNjYW4gZW5kdGV4dCBlbmR0cnkgZW5kd2l0aCBlcnJvciBleGl0IGZpbmFsbHkgZm9yIGZyb20gZnVuY3Rpb24gZnVuYyBoaWRkZW4gaWYgbG9jYWwgbHBhcmFtZXRlciBscGFyYW1ldGVycyBuZXh0IG5vc2hvdyBvdGhlcndpc2UgcGFyYW1ldGVycyBwcmludGpvYiBwcm9jZWR1cmUgcHJvYyBwcm90ZWN0ZWQgcHVibGljfHNjYW4gdGV4dCB0aGVuIHRocm93IHRvIHRyeSB3aGlsZSB3aXRoIGFjdGl2YXRlIGFkZCBhbHRlciBhbHRlcm5hdGUgYW5zaSBhcHAgYXBwZW5kIGFycmF5IGFzc2VydCBhc3NlcnRzIGFzc2lzdCBhdXRvaW5jZXJyb3IgYXV0b3NhdmUgYXZlcmFnZSBiYXIgYmVnaW4gYmVsbCBibGFuayBibG9ja3NpemUgYm9yZGVyIGJveCBicm93c2UgYnJvd3NlaW1lIGJyc3RhdHVzIGJ1aWxkIGNhbGN1bGF0ZSBjYWxsIGNhbmNlbCBjYXJyeSBjYXRjaCBjZCBjZW50dXJ5IGNoYW5nZSBjaGRpciBjbGFzcyBjbGFzc2xpYiBjbGVhciBjbG9jayBjbG9zZSBjb2xsYXRlIGNvbG9yIGNvbXBhdGlibGUgY29tcGlsZSBjb25maXJtIGNvbm5lY3Rpb24gY29ubmVjdGlvbnMgY29uc29sZSBjb250aW51ZSBjb3B5IGNvdW50IGNvdmVyYWdlIGNwY29tcGlsZSBjcGRpYWxvZyBjcmVhdGUgY3VycmVuY3kgY3Vyc29yIGN1cnNvciBkYXRhYmFzZSBkYXRhc2Vzc2lvbiBkYXRlIGRlYWN0aXZhdGUgZGVidWcgZGVidWdvdXQgZGVjaW1hbHMgZGVjbGFyZSBkZWZhdWx0IGRlZmluZSBkZWxldGUgZGVsZXRlZCBkZWxpbWl0ZXJzIGRldmVsb3BtZW50IGRldmljZSBkaW1lbnNpb24gZGlyIGRpcmVjdG9yeSBkaXNwbGF5IGRsbCBkbGxzIGRvY2sgZG9ldmVudHMgZG9oaXN0b3J5IGRyb3AgZWNobyBlZGl0IGVqZWN0IGVuZCBlbmdpbmViZWhhdmlvciBlcmFzZSBlcnJvciBlc2NhcGUgZXZlbnRsaXN0IGV2ZW50cyBldmVudHRyYWNraW5nIGV4YWN0IGV4Y2x1c2l2ZSBleGUgZXhwb3J0IGV4dGVuZGVkIGV4dGVybmFsIGZkb3cgZmllbGRzIGZpbGUgZmlsZXMgZmlsdGVyIGZpbmFsbHkgZmluZCBmaXhlZCBmbHVzaCBmb3JtIGZvcm1hdCBmcmVlIGZyb20gZnVsbHBhdGggZnVuY3Rpb24gZndlZWsgZ2F0aGVyIGdlbmVyYWwgZ2V0IGdldGV4cHIgZ2V0cyBnbyBnb3RvIGhlYWRpbmdzIGhlbHAgaGlkZSBob3VycyBpZCBpbXBvcnQgaW4gaW5kZXggaW5kZXhlcyBpbnB1dCBpbnNlcnQgaW50ZW5zaXR5IGludG8gam9pbiBrZXkga2V5Ym9hcmQga2V5Y29tcCBsYWJlbCBsaWJyYXJ5IGxpc3QgbG9hZCBsb2NhbCBsb2NhdGUgbG9jayBsb2dlcnJvcnMgbG9vcCBscGFyYW1ldGVycyBtYWNrZXkgbWFjcm8gbWFjcm9zIG1hcmdpbiBtYXJrIG1kIG1lbW8gbWVtb3J5IG1lbW93aWR0aCBtZW51IG1lbnVzIG1lc3NhZ2UgbWtkaXIgbW9kaWZ5IG1vdXNlIG1vdmUgbXRkbGwgbXVsdGlsb2NrcyBuZWFyIG5vY3B0cmFucyBub3RlIG5vdGlmeSBudWxsZGlzcGxheSBub3dzaG93IG9iamVjdCBvYmplY3RzIG9kb21ldGVyIG9mIG9mZiBvbGVvYmplY3Qgb24gb3BlbiBvcHRpbWl6ZSBvcmRlciBwYWNrIHBhZCBwYWdlIHBhbGV0dGUgcGFyYW1ldGVycyBwYXRoIHBkc2V0dXAgcGxheSBwb2ludCBwb3AgcG9wdXAgcG9wdXBzIHByaW50ZXIgcHJpdmF0ZSBwcm9jZWR1cmUgcHJvY2VkdXJlcyBwcm9qZWN0IHB1YmxpYyBwdXNoIHF1ZXJ5IHF1aXRyZCByZWFkIHJlYWRib3JkZXIgcmVhZGVycm9yIHJlY2FsbCByZWZyZXNoIHJlaW5kZXggcmVsYXRpb24gcmVsZWFzZSByZW1vdmUgcmVuYW1lIHJlcGxhY2UgcmVwb3J0IHJlcHJvY2VzcyByZXNvdXJjZSByZXN0b3JlIHJlc3VtZSByZXRyeSByZXR1cm4gcm1kaXIgcm9sbGJhY2sgcnVuIHNhZmV0eSBzYXZlIHNjYW4gc2NhdHRlciBzY2hlbWUgc2NyZWVuIHNjcm9sbCBzZWNvbmRzIHNlZWsgc2VsZWN0IHNlbGVjdGlvbiBzZXBhcmF0b3Igc2V0IHNob3cgc2h1dGRvd24gc2l6ZSBza2lwIHNraXAgc29ydCBzcGFjZSBzcWwgc3RhdHVzIHN0ZXAgc3RvcmUgc3RyaWN0ZGF0ZSBzdHJ1Y3R1cmUgc3VtIHN1c3BlbmQgc3lzZm9ybWF0cyBzeXNtZW51IHRhYmxlIHRhYmxlcyB0YWJsZXZhbGlkYXRlIHRhZyB0YWxrIHRleHRtZXJnZSB0aGlzIHRocm93IHRvIHRvcGljIHRvdGFsIHRyYW5zYWN0aW9uIHRyYmV0d2VlbiB0cmlnZ2VyIHRyeSB0eXBlIHR5cGVhaGVhZCB1ZGZwYXJtcyB1bmJpbmRldmVudHMgdW5pcXVlIHVubG9jayB1cGRhdGUgdXNlIHZhbGlkYXRlIHZpZXcgdmlld3Mgd2FpdCB3aGVyZSB3aW5kb3cgd2luZG93cyB3aW5kb3dzIHdpbjMyYXBpIHphcCB6b29tIixidWlsdF9pbjoiYWJzIGFjbGFzcyBhY29weSBhY29zIGFkYXRhYmFzZXMgYWRib2JqZWN0cyBhZGRicyBhZGRwcm9wZXJ0eSBhZGVsIGFkaXIgYWRsbHMgYWRvY2tzdGF0ZSBhZWxlbWVudCBhZXJyb3IgYWV2ZW50cyBhZmllbGRzIGFmb250IGFnZXRjbGFzcyBhZ2V0ZmlsZXZlcnNpb24gYWlucyBhaW5zdGFuY2UgYWxhbmd1YWdlIGFsZW4gYWxpYXMgYWxpbmVzIGFsbHRyaW0gYW1lbWJlcnMgYW1vdXNlb2JqIGFuZXRyZXNvdXJjZXMgYXByaW50ZXJzIGFwcm9jaW5mbyBhc2MgYXNjYW4gYXNlbG9iaiBhc2Vzc2lvbnMgYXNpbiBhc29ydCBhc3RhY2tpbmZvIGFzdWJzY3JpcHQgYXQgYXRfYyBhdGFnaW5mbyBhdGFuIGF0YyBhdGNjIGF0Y2xpbmUgYXRsaW5lIGF0bjIgYXVzZWQgYXZjeGNsYXNzZXMgYmFyIGJhcmNvdW50IGJhcnByb21wdCBiZXR3ZWVuIGJpbmRldmVudCBiaW50b2MgYml0YW5kIGJpdGNsZWFyIGJpdGxzaGlmdCBiaXRub3QgYml0b3IgYml0cnNoaWZ0IGJpdHNldCBiaXR0ZXN0IGJpdHhvciBib2YgIGNhbmRpZGF0ZSBjYXBzbG9jayBjZG93IGNkeCBjZWlsaW5nIGNociBjaHJzYXcgY2hydHJhbiBjaHJ0cmFuYyBjbW9udGggY250YmFyIGNudHBhZCBjb2wgY29tIGNvbWFycmF5IGNvbWNsYXNzaW5mbyBjb21wb2JqIGNvbXByb3AgY29tcmV0dXJuZXJyb3IgY29zIGNwY29udmVydCBjcGN1cnJlbnQgY3BkYmYgY3JlYXRlYmluYXJ5IGNyZWF0ZW9iamVjdCBjcmVhdGVvYmplY3RleCBjcmVhdGVvZmZsaW5lIGN0b2JpbiBjdG9kIGN0b3QgY3VyZGlyIGN1cnNvcmdldHByb3AgY3Vyc29yc2V0cHJvcCBjdXJzb3J0b3htbCBjdXJ2YWwgZGF0ZSBkYXRldGltZSBkYXkgZGJjIGRiZiBkYmdldHByb3AgZGJzZXRwcm9wIGRidXNlZCBkZGVhYm9ydHRyYW5zIGRkZWFkdmlzZSBkZGVlbmFibGVkIGRkZWV4ZWN1dGUgZGRlaW5pdGlhdGUgZGRlbGFzdGVycm9yIGRkZXBva2UgZGRlcmVxdWVzdCBkZGVzZXRvcHRpb24gZGRlc2V0c2VydmljZSBkZGVzZXR0b3BpYyBkZGV0ZXJtaW5hdGUgZGVmYXVsdGV4dCBkZWxldGVkIGRlc2NlbmRpbmcgZGlmZmVyZW5jZSBkaXJlY3RvcnkgZGlza3NwYWNlIGRpc3BsYXlwYXRoIGRteSBkb2RlZmF1bHQgZG9ldmVudHMgZG93IGRyaXZldHlwZSBkcm9wb2ZmbGluZSBkdG9jIGR0b3IgZHRvcyBkdG90IGVkaXRzb3VyY2UgZW1wdHkgZW9mIGVycm9yIGV2YWx1YXRlIGV2ZW50aGFuZGxlciBldmwgZXhlY3NjcmlwdCBleHAgIGZjaHNpemUgZmNsb3NlIGZjb3VudCBmY3JlYXRlIGZkYXRlIGZlb2YgZmVycm9yIGZmbHVzaCBmZ2V0cyBmaWVsZCBmaWxlIGZpbGV0b3N0ciBmaWx0ZXIgZmtsYWJlbCBma21heCBmbGRsaXN0IGZsb2NrIGZsb29yIGZvbnRtZXRyaWMgZm9wZW4gZm9yY2VleHQgZm9yY2VwYXRoIGZvdW5kIGZwdXRzIGZyZWFkIGZzZWVrIGZzaXplIGZ0aW1lIGZ1bGxwYXRoIGZ1bmN0aW9uIGNvbW1hbmQgZnYgZndyaXRlICBnZXRiYXIgZ2V0Y29sb3IgZ2V0Y3AgZ2V0ZGlyIGdldGVudiBnZXRmaWxlIGdldGZsZHN0YXRlIGdldGZvbnQgZ2V0aW50ZXJmYWNlIGdldG5leHRtb2RpZmllZCBnZXRvYmplY3QgZ2V0cGFkIGdldHBlbSBnZXRwaWN0IGdldHByaW50ZXIgZ2V0d29yZGNvdW50IGdldHdvcmRudW0gZ2V0Y3Vyc29yYWRhcHRlciBnb21vbnRoICBoZWFkZXIgaG9tZSBob3VyIGlkeGNvbGxhdGUgaWlmIGltZXN0YXR1cyBpbmRiYyBpbmRleHNlZWsgaW5rZXkgaW5saXN0IGlucHV0Ym94IGluc21vZGUgaW50IGludGVnZXIgaXNhbHBoYSBpc2JsYW5rIGlzY29sb3IgaXNkaWdpdCBpc2V4Y2x1c2l2ZSBpc2Zsb2NrZWQgaXNsZWFkYnl0ZSBpc2xvd2VyIGlzbW91c2UgaXNudWxsIGlzcmVhZG9ubHkgaXNybG9ja2VkIGlzdXBwZXIgIGp1c3Rkcml2ZSBqdXN0ZXh0IGp1c3RmbmFtZSBqdXN0cGF0aCBqdXN0c3RlbSAga2V5IGtleW1hdGNoICBsYXN0a2V5IGxlZnQgbGVmdGMgbGVuIGxlbmMgbGlrZSBsaWtlYyBsaW5lbm8gbG9hZHBpY3R1cmUgbG9jZmlsZSBsb2NrIGxvZyBsb2cxMCBsb29rdXAgbG93ZXIgbHRyaW0gbHVwZGF0ZSAgbWF4IG1jb2wgbWRvd24gbWR4IG1keSBtZW1saW5lcyBtZW1vcnkgbWVudSBtZXNzYWdlIG1lc3NhZ2Vib3ggbWluIG1pbnV0ZSBtbGluZSBtb2QgbW9udGggbXJrYmFyIG1ya3BhZCBtcm93IG10b24gbXdpbmRvdyAgbmR4IG5ld29iamVjdCBub3JtYWxpemUgbm93YWl0IG5vc2hvdyBudG9tIG51bWxvY2sgbnZsICBvYmpudW0gb2JqdG9jbGllbnQgb2JqdmFyIG9jY3VycyBvZW10b2Fuc2kgb2xkdmFsIG9uIG9yZGVyIG9zICBwYWQgcGFkbCBwYWRyIHBhZGMgcGFyYW1ldGVycyBwYXltZW50IHBjb2wgcGNvdW50IHBlbXN0YXR1cyBwaSBwb3B1cCBwcmltYXJ5IHByaW50c3RhdHVzIHBybWJhciBwcm1wYWQgcHJvZ3JhbSBwcm9tcHQgcHJvcGVyIHByb3cgcHJ0aW5mbyBwdXRmaWxlIHB2IHF1YXJ0ZXIgIHJhaXNlZXZlbnQgcmFuZCByYXQgcmF0YyByYXRsaW5lIHJkbGV2ZWwgcmVhZGtleSByZWNjb3VudCByZWNubyByZWNzaXplIHJlZnJlc2ggcmVsYXRpb24gcmVwbGljYXRlIHJlcXVlcnkgcmdiIHJnYnNjaGVtZSByaWdodCByaWdodGMgcmxvY2sgcm91bmQgcm93IHJ0b2QgcnRyaW0gIHNhdmVwaWN0dXJlIHNjaGVtZSBzY29scyBzZWMgc2Vjb25kcyBzZWVrIHNldCBzZXRmbGRzdGF0ZSBzaWduIHNpbiBza3BiYXIgc2twcGFkIHNvdW5kZXggc3BhY2Ugc3FsY2FuY2VsIHNxbGNvbHVtbnMgc3FsY29tbWl0IHNxbGNvbm5lY3Qgc3FsZGlzY29ubmVjdCBzcWxleGVjIHNxbGdldHByb3Agc3FsbW9yZXJlc3VsdHMgc3FscHJlcGFyZSBzcWxyb2xsYmFjayBzcWxzZXRwcm9wIHNxbHN0cmluZ2Nvbm5lY3Qgc3FsdGFibGVzIHNxcnQgc3Jvd3Mgc3RyIHN0cmNvbnYgc3RyZXh0cmFjdCBzdHJ0b2ZpbGUgc3RydHJhbiBzdHVmZiBzdHVmZmMgc3Vic3RyIHN1YnN0cmMgc3lzcyBvdmVydmlldyBzeXNtZXRyaWMgdGFibGVyZXZlcnQgdGFibGV1cGRhdGUgdGFnIHRhZ2NvdW50IHRhZ25vIHRhbiB0YXJnZXQgdGV4dG1lcmdlIHRpbWUgdHJhbnNmb3JtIHRyaW0gdHRvYyB0dG9kIHR4bmxldmVsIHR4dHdpZHRoIHR5cGUgdW5iaW5kZXZlbnRzIHVuaXF1ZSB1cGRhdGVkIHVwcGVyIHVzZWQgdmFsIHZhcnJlYWQgdmFydHlwZSB2ZXJzaW9uIHdib3JkZXIgd2NoaWxkIHdjb2xzIHdkb2NrYWJsZSB3ZWVrIHdleGlzdCB3Zm9udCB3bGFzdCB3bGNvbCB3bHJvdyB3bWF4aW11bSB3bWluaW11bSB3b250b3Agd291dHB1dCB3cGFyZW50IHdyZWFkIHdyb3dzIHd0aXRsZSB3dmlzaWJsZSB4bWx0b2N1cnNvciB4bWx1cGRhdGVncmFtIHllYXJfYWxpZ25tZW50IF9hc2NpaWNvbHMgX2FzY2lpcm93cyBfYXNzaXN0IF9iZWF1dGlmeSBfYm94IF9icm93c2VyIF9idWlsZGVyIF9jYWxjbWVtIF9jYWxjdmFsdWUgX2NsaXB0ZXh0IF9jb252ZXJ0ZXIgX2NvdmVyYWdlIF9jb3ZlcmFnZSBfY3Vyb2JqIF9kYmxjbGljayBfZGlhcnlkYXRlIF9kb3MgX2ZveGRvYyBfZm94Z3JhcGggX2dhbGxlcnkgX2dlbmdyYXBoIF9nZW5odG1sIF9nZW5tZW51IF9nZW5wZCBfZ2Vuc2NybiBfZ2VueHRhYiBfZ2V0ZXhwciBfaW5jbHVkZSBfaW5kZW50IF9sbWFyZ2luIF9tYWMgX21kYV9hcHBuZCBfbWRhX2F2ZyBfbWRhX2Jyb3cgX21kYV9jYWxjIF9tZGFfY29weSBfbWRhX2NvdW50IF9tZGFfbGFiZWwgX21kYV9wYWNrIF9tZGFfcmVwcnQgX21kYV9yaW5keCBfbWRhX3NldHVwIF9tZGFfc29ydCBfbWRhX3NwMTAwIF9tZGFfc3AyMDAgX21kYV9zcDMwMCBfbWRhX3N1bSBfbWRhX3RvdGFsIF9tZGF0YSBfbWRpYXJ5IF9tZWRfY2xlYXIgX21lZF9jb3B5IF9tZWRfY3V0IF9tZWRfY3Z0c3QgX21lZF9maW5kIF9tZWRfZmluZGEgX21lZF9nb3RvIF9tZWRfaW5zb2IgX21lZF9saW5rIF9tZWRfb2JqIF9tZWRfcGFzdGUgX21lZF9wcmVmIF9tZWRfcHN0bGsgX21lZF9yZWRvIF9tZWRfcmVwbCBfbWVkX3JlcGxhIF9tZWRfc2xjdGEgX21lZF9zcDEwMCBfbWVkX3NwMjAwIF9tZWRfc3AzMDAgX21lZF9zcDQwMCBfbWVkX3NwNTAwIF9tZWRfdW5kbyBfbWVkaXQgX21maV9jbGFsbCBfbWZpX2Nsb3NlIF9tZmlfZXhwb3J0IF9tZmlfaW1wb3J0IF9tZmlfbmV3IF9tZmlfb3BlbiBfbWZpX3Bnc2V0IF9tZmlfcHJldnUgX21maV9wcmludCBfbWZpX3F1aXQgX21maV9yZXZydCBfbWZpX3NhdmFzIF9tZmlfc2F2ZSBfbWZpX3NlbmQgX21maV9zZXR1cCBfbWZpX3NwMTAwIF9tZmlfc3AyMDAgX21maV9zcDMwMCBfbWZpX3NwNDAwIF9tZmlsZSBfbWZpbGVyIF9tZmlyc3QgX21sYWJlbCBfbWxhc3QgX21saW5lIF9tbWFjcm8gX21tYmxkciBfbXByX2JlYXV0IF9tcHJfY2FuY2wgX21wcl9jb21wbCBfbXByX2RvIF9tcHJfZG9jdW0gX21wcl9mb3Jtd3ogX21wcl9nZW5lciBfbXByX2dyYXBoIF9tcHJfcmVzdW0gX21wcl9zcDEwMCBfbXByX3NwMjAwIF9tcHJfc3AzMDAgX21wcl9zdXNwZW5kIF9tcHJvZyBfbXByb2ogX21yY19hcHBuZCBfbXJjX2NobmdlIF9tcmNfY29udCBfbXJjX2RlbGV0IF9tcmNfZ290byBfbXJjX2xvY2F0IF9tcmNfcmVjYWwgX21yY19yZXBsIF9tcmNfc2VlayBfbXJjX3NwMTAwIF9tcmNfc3AyMDAgX21yZWNvcmQgX21yZXBvcnQgX21ycWJlIF9tc2NyZWVuIF9tc21fZGF0YSBfbXNtX2VkaXQgX21zbV9maWxlIF9tc21fZm9ybWF0IF9tc21fcHJvZyBfbXNtX3JlY3JkIF9tc21fc3lzdG0gX21zbV90ZXh0IF9tc21fdG9vbHMgX21zbV92aWV3IF9tc21fd2luZG8gX21zdF9hYm91dCBfbXN0X2FzY2lpIF9tc3RfY2FsY3UgX21zdF9jYXB0ciBfbXN0X2RiYXNlIF9tc3RfZGlhcnkgX21zdF9maWxlciBfbXN0X2hlbHAgX21zdF9ocGhvdyBfbXN0X2hwc2NoIF9tc3RfbWFjcm8gX21zdF9vZmZpY2UgX21zdF9wdXp6bCBfbXN0X3NwMTAwIF9tc3Rfc3AyMDAgX21zdF9zcDMwMCBfbXN0X3NwZWNsIF9tc3lzbWVudSBfbXN5c3RlbSBfbXRhYmxlIF9tdGJfYXBwbmQgX210Yl9jcGFydCBfbXRiX2RlbGV0IF9tdGJfZGVscmMgX210Yl9nb3RvIF9tdGJfbGluayBfbXRiX212ZmxkIF9tdGJfbXZwcnQgX210Yl9wcm9wcyBfbXRiX3JlY2FsIF9tdGJfc3AxMDAgX210Yl9zcDIwMCBfbXRiX3NwMzAwIF9tdGJfc3A0MDAgX210Yl9zemZsZCBfbXdpX2FycmFuIF9td2lfY2xlYXIgX213aV9jbWQgX213aV9jb2xvciBfbXdpX2RlYnVnIF9td2lfaGlkZSBfbXdpX2hpZGVhIF9td2lfbWluIF9td2lfbW92ZSBfbXdpX3JvdGF0IF9td2lfc2hvd2EgX213aV9zaXplIF9td2lfc3AxMDAgX213aV9zcDIwMCBfbXdpX3Rvb2xiIF9td2lfdHJhY2UgX213aV92aWV3IF9td2lfem9vbSBfbXdpbmRvdyBfbXdpemFyZHMgX213el9hbGwgX213el9mb3JtIF9td3pfZm94ZG9jIF9td3pfaW1wb3J0IF9td3pfbGFiZWwgX213el9tYWlsIF9td3pfcGl2b3QgX213el9xdWVyeSBfbXd6X3JlcHJ0IF9td3pfc2V0dXAgX213el90YWJsZSBfbXd6X3Vwc2l6aW5nIF9uZXR3YXJlIF9vcmFjbGUgX3BhZHZhbmNlIF9wYWdlbm8gX3BicGFnZSBfcGNvbG5vIF9wY29waWVzIF9wZHBhcm1zIF9wZHJpdmVyIF9wZHNldHVwIF9wZWNvZGUgX3BlamVjdCBfcGVwYWdlIF9wZm9ybSBfcGxlbmd0aCBfcGxpbmVubyBfcGxvZmZzZXQgX3BwaXRjaCBfcHF1YWxpdHkgX3ByZXRleHQgX3BzY29kZSBfcHNwYWNpbmcgX3B3YWl0IF9ybWFyZ2luIF9ydW5hY3RpdmVkb2MgX3NhbXBsZXMgX3NjcmVlbiBfc2hlbGwgX3NwZWxsY2hrIF9zcWxzZXJ2ZXIgX3N0YXJ0dXAgX3RhYnMgX3RhbGx5IF90ZXh0IF90aHJvdHRsZSBfdHJhbnNwb3J0IF90cmlnZ2VybGV2ZWwgX3VuaXggX3dlYmRldm9ubHkgX3dlYm1lbnUgX3dlYm1zZnRob21lcGFnZSBfd2VidmZwaG9tZXBhZ2UgX3dlYnZmcG9ubGluZXN1cHBvcnQgX3dpbmRvd3MgX3dpemFyZCBfd3JhcCBfc2NjdGV4dCBfdmZwIixsaXRlcmFsOiJcXC50XFwuIFxcLmZcXC4gbnVsbCJ9LGk6Ii8vIixjOlt7Y046InN0cmluZyIsYjoiJyIsZToiJyJ9LHtjTjoic3RyaW5nIixiOiciJyxlOiciJ30se2NOOiJzdHJpbmciLGI6IlxcWyIsZToiXFxdIn0se2NOOiJtZXRhIixiOiIjIixlOiIkIixrOnsibWV0YS1rZXl3b3JkIjoiI2lmICNlbHNlaWYgI2VuZGlmICNkZWZpbmUgI3VuZGVmaW5lIn19LGUuQygvKF5ccypcKil8KFwmXCYpLywvJC8se3I6MH0pLGUuQ05NXX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImZzaGFycCIsZnVuY3Rpb24oZSl7dmFyIHQ9e2I6IjwiLGU6Ij4iLGM6W2UuaW5oZXJpdChlLlRNLHtiOi8nW2EtekEtWjAtOV9dKy99KV19O3JldHVybnthbGlhc2VzOlsiZnMiXSxrOiJhYnN0cmFjdCBhbmQgYXMgYXNzZXJ0IGJhc2UgYmVnaW4gY2xhc3MgZGVmYXVsdCBkZWxlZ2F0ZSBkbyBkb25lIGRvd25jYXN0IGRvd250byBlbGlmIGVsc2UgZW5kIGV4Y2VwdGlvbiBleHRlcm4gZmFsc2UgZmluYWxseSBmb3IgZnVuIGZ1bmN0aW9uIGdsb2JhbCBpZiBpbiBpbmhlcml0IGlubGluZSBpbnRlcmZhY2UgaW50ZXJuYWwgbGF6eSBsZXQgbWF0Y2ggbWVtYmVyIG1vZHVsZSBtdXRhYmxlIG5hbWVzcGFjZSBuZXcgbnVsbCBvZiBvcGVuIG9yIG92ZXJyaWRlIHByaXZhdGUgcHVibGljIHJlYyByZXR1cm4gc2lnIHN0YXRpYyBzdHJ1Y3QgdGhlbiB0byB0cnVlIHRyeSB0eXBlIHVwY2FzdCB1c2UgdmFsIHZvaWQgd2hlbiB3aGlsZSB3aXRoIHlpZWxkIixpOi9cL1wqLyxjOlt7Y046ImtleXdvcmQiLGI6L1xiKHlpZWxkfHJldHVybnxsZXR8ZG8pIS99LHtjTjoic3RyaW5nIixiOidAIicsZTonIicsYzpbe2I6JyIiJ31dfSx7Y046InN0cmluZyIsYjonIiIiJyxlOiciIiInfSxlLkMoIlxcKFxcKiIsIlxcKlxcKSIpLHtjTjoiY2xhc3MiLGJLOiJ0eXBlIixlOiJcXCh8PXwkIixlRTohMCxjOltlLlVUTSx0XX0se2NOOiJtZXRhIixiOiJcXFs8IixlOiI+XFxdIixyOjEwfSx7Y046InN5bWJvbCIsYjoiXFxCKCdbQS1aYS16XSlcXGIiLGM6W2UuQkVdfSxlLkNMQ00sZS5pbmhlcml0KGUuUVNNLHtpOm51bGx9KSxlLkNOTV19fSksby5yZWdpc3Rlckxhbmd1YWdlKCJnbyIsZnVuY3Rpb24oZSl7dmFyIHQ9e2tleXdvcmQ6ImJyZWFrIGRlZmF1bHQgZnVuYyBpbnRlcmZhY2Ugc2VsZWN0IGNhc2UgbWFwIHN0cnVjdCBjaGFuIGVsc2UgZ290byBwYWNrYWdlIHN3aXRjaCBjb25zdCBmYWxsdGhyb3VnaCBpZiByYW5nZSB0eXBlIGNvbnRpbnVlIGZvciBpbXBvcnQgcmV0dXJuIHZhciBnbyBkZWZlciBib29sIGJ5dGUgY29tcGxleDY0IGNvbXBsZXgxMjggZmxvYXQzMiBmbG9hdDY0IGludDggaW50MTYgaW50MzIgaW50NjQgc3RyaW5nIHVpbnQ4IHVpbnQxNiB1aW50MzIgdWludDY0IGludCB1aW50IHVpbnRwdHIgcnVuZSIsbGl0ZXJhbDoidHJ1ZSBmYWxzZSBpb3RhIG5pbCIsYnVpbHRfaW46ImFwcGVuZCBjYXAgY2xvc2UgY29tcGxleCBjb3B5IGltYWcgbGVuIG1ha2UgbmV3IHBhbmljIHByaW50IHByaW50bG4gcmVhbCByZWNvdmVyIGRlbGV0ZSJ9O3JldHVybnthbGlhc2VzOlsiZ29sYW5nIl0sazp0LGk6IjwvIixjOltlLkNMQ00sZS5DQkNNLHtjTjoic3RyaW5nIix2OltlLlFTTSx7YjoiJyIsZToiW15cXFxcXScifSx7YjoiYCIsZToiYCJ9XX0se2NOOiJudW1iZXIiLHY6W3tiOmUuQ05SKyJbaV0iLHI6MX0sZS5DTk1dfSx7YjovOj0vfSx7Y046ImZ1bmN0aW9uIixiSzoiZnVuYyIsZTovXHMqXHsvLGVFOiEwLGM6W2UuVE0se2NOOiJwYXJhbXMiLGI6L1woLyxlOi9cKS8sazp0LGk6L1siJ10vfV19XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImh0dHAiLGZ1bmN0aW9uKGUpe3ZhciB0PSJIVFRQL1swLTlcXC5dKyI7cmV0dXJue2FsaWFzZXM6WyJodHRwcyJdLGk6IlxcUyIsYzpbe2I6Il4iK3QsZToiJCIsYzpbe2NOOiJudW1iZXIiLGI6IlxcYlxcZHszfVxcYiJ9XX0se2I6Il5bQS1aXSsgKC4qPykgIit0KyIkIixyQjohMCxlOiIkIixjOlt7Y046InN0cmluZyIsYjoiICIsZToiICIsZUI6ITAsZUU6ITB9LHtiOnR9LHtjTjoia2V5d29yZCIsYjoiW0EtWl0rIn1dfSx7Y046ImF0dHJpYnV0ZSIsYjoiXlxcdyIsZToiOiAiLGVFOiEwLGk6IlxcbnxcXHN8PSIsc3RhcnRzOntlOiIkIixyOjB9fSx7YjoiXFxuXFxuIixzdGFydHM6e3NMOltdLGVXOiEwfX1dfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgiaW5pIixmdW5jdGlvbihlKXt2YXIgdD17Y046InN0cmluZyIsYzpbZS5CRV0sdjpbe2I6IicnJyIsZToiJycnIixyOjEwfSx7YjonIiIiJyxlOiciIiInLHI6MTB9LHtiOiciJyxlOiciJ30se2I6IiciLGU6IicifV19O3JldHVybnthbGlhc2VzOlsidG9tbCJdLGNJOiEwLGk6L1xTLyxjOltlLkMoIjsiLCIkIiksZS5IQ00se2NOOiJzZWN0aW9uIixiOi9eXHMqXFsrLyxlOi9cXSsvfSx7YjovXlthLXowLTlcW1xdX1wuLV0rXHMqPVxzKi8sZToiJCIsckI6ITAsYzpbe2NOOiJhdHRyIixiOi9bYS16MC05XFtcXV9cLi1dKy99LHtiOi89LyxlVzohMCxyOjAsYzpbZS5DKCI7IiwiJCIpLGUuSENNLHtjTjoibGl0ZXJhbCIsYjovXGJvbnxvZmZ8dHJ1ZXxmYWxzZXx5ZXN8bm9cYi99LHtjTjoidmFyaWFibGUiLHY6W3tiOi9cJFtcd1xkIl1bXHdcZF9dKi99LHtiOi9cJFx7KC4qPyl9L31dfSx0LHtjTjoibnVtYmVyIixiOi8oW1wrXC1dKyk/W1xkXStfW1xkX10rL30sZS5OTV19XX1dfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgiamF2YSIsZnVuY3Rpb24oZSl7dmFyIHQ9ImZhbHNlIHN5bmNocm9uaXplZCBpbnQgYWJzdHJhY3QgZmxvYXQgcHJpdmF0ZSBjaGFyIGJvb2xlYW4gdmFyIHN0YXRpYyBudWxsIGlmIGNvbnN0IGZvciB0cnVlIHdoaWxlIGxvbmcgc3RyaWN0ZnAgZmluYWxseSBwcm90ZWN0ZWQgaW1wb3J0IG5hdGl2ZSBmaW5hbCB2b2lkIGVudW0gZWxzZSBicmVhayB0cmFuc2llbnQgY2F0Y2ggaW5zdGFuY2VvZiBieXRlIHN1cGVyIHZvbGF0aWxlIGNhc2UgYXNzZXJ0IHNob3J0IHBhY2thZ2UgZGVmYXVsdCBkb3VibGUgcHVibGljIHRyeSB0aGlzIHN3aXRjaCBjb250aW51ZSB0aHJvd3MgcHJvdGVjdGVkIHB1YmxpYyBwcml2YXRlIG1vZHVsZSByZXF1aXJlcyBleHBvcnRzIGRvIixyPXtjTjoibnVtYmVyIixiOiJcXGIoMFtiQl0oWzAxXStbMDFfXStbMDFdK3xbMDFdKyl8MFt4WF0oW2EtZkEtRjAtOV0rW2EtZkEtRjAtOV9dK1thLWZBLUYwLTldK3xbYS1mQS1GMC05XSspfCgoW1xcZF0rW1xcZF9dK1tcXGRdK3xbXFxkXSspKFxcLihbXFxkXStbXFxkX10rW1xcZF0rfFtcXGRdKykpP3xcXC4oW1xcZF0rW1xcZF9dK1tcXGRdK3xbXFxkXSspKShbZUVdWy0rXT9cXGQrKT8pW2xMZkZdPyIscjowfTtyZXR1cm57YWxpYXNlczpbImpzcCJdLGs6dCxpOi88XC98Iy8sYzpbZS5DKCIvXFwqXFwqIiwiXFwqLyIse3I6MCxjOlt7YjovXHcrQC8scjowfSx7Y046ImRvY3RhZyIsYjoiQFtBLVphLXpdKyJ9XX0pLGUuQ0xDTSxlLkNCQ00sZS5BU00sZS5RU00se2NOOiJjbGFzcyIsYks6ImNsYXNzIGludGVyZmFjZSIsZTovW3s7PV0vLGVFOiEwLGs6ImNsYXNzIGludGVyZmFjZSIsaTovWzoiXFtcXV0vLGM6W3tiSzoiZXh0ZW5kcyBpbXBsZW1lbnRzIn0sZS5VVE1dfSx7Yks6Im5ldyB0aHJvdyByZXR1cm4gZWxzZSIscjowfSx7Y046ImZ1bmN0aW9uIixiOiIoW8OALcq4YS16QS1aXyRdW8OALcq4YS16QS1aXyQwLTldKig8W8OALcq4YS16QS1aXyRdW8OALcq4YS16QS1aXyQwLTldKihcXHMqLFxccypbw4AtyrhhLXpBLVpfJF1bw4AtyrhhLXpBLVpfJDAtOV0qKSo+KT9cXHMrKSsiK2UuVUlSKyJcXHMqXFwoIixyQjohMCxlOi9bezs9XS8sZUU6ITAsazp0LGM6W3tiOmUuVUlSKyJcXHMqXFwoIixyQjohMCxyOjAsYzpbZS5VVE1dfSx7Y046InBhcmFtcyIsYjovXCgvLGU6L1wpLyxrOnQscjowLGM6W2UuQVNNLGUuUVNNLGUuQ05NLGUuQ0JDTV19LGUuQ0xDTSxlLkNCQ01dfSxyLHtjTjoibWV0YSIsYjoiQFtBLVphLXpdKyJ9XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImphdmFzY3JpcHQiLGZ1bmN0aW9uKGUpe3ZhciB0PSJbQS1aYS16JF9dWzAtOUEtWmEteiRfXSoiLHI9e2tleXdvcmQ6ImluIG9mIGlmIGZvciB3aGlsZSBmaW5hbGx5IHZhciBuZXcgZnVuY3Rpb24gZG8gcmV0dXJuIHZvaWQgZWxzZSBicmVhayBjYXRjaCBpbnN0YW5jZW9mIHdpdGggdGhyb3cgY2FzZSBkZWZhdWx0IHRyeSB0aGlzIHN3aXRjaCBjb250aW51ZSB0eXBlb2YgZGVsZXRlIGxldCB5aWVsZCBjb25zdCBleHBvcnQgc3VwZXIgZGVidWdnZXIgYXMgYXN5bmMgYXdhaXQgc3RhdGljIGltcG9ydCBmcm9tIGFzIixsaXRlcmFsOiJ0cnVlIGZhbHNlIG51bGwgdW5kZWZpbmVkIE5hTiBJbmZpbml0eSIsYnVpbHRfaW46ImV2YWwgaXNGaW5pdGUgaXNOYU4gcGFyc2VGbG9hdCBwYXJzZUludCBkZWNvZGVVUkkgZGVjb2RlVVJJQ29tcG9uZW50IGVuY29kZVVSSSBlbmNvZGVVUklDb21wb25lbnQgZXNjYXBlIHVuZXNjYXBlIE9iamVjdCBGdW5jdGlvbiBCb29sZWFuIEVycm9yIEV2YWxFcnJvciBJbnRlcm5hbEVycm9yIFJhbmdlRXJyb3IgUmVmZXJlbmNlRXJyb3IgU3RvcEl0ZXJhdGlvbiBTeW50YXhFcnJvciBUeXBlRXJyb3IgVVJJRXJyb3IgTnVtYmVyIE1hdGggRGF0ZSBTdHJpbmcgUmVnRXhwIEFycmF5IEZsb2F0MzJBcnJheSBGbG9hdDY0QXJyYXkgSW50MTZBcnJheSBJbnQzMkFycmF5IEludDhBcnJheSBVaW50MTZBcnJheSBVaW50MzJBcnJheSBVaW50OEFycmF5IFVpbnQ4Q2xhbXBlZEFycmF5IEFycmF5QnVmZmVyIERhdGFWaWV3IEpTT04gSW50bCBhcmd1bWVudHMgcmVxdWlyZSBtb2R1bGUgY29uc29sZSB3aW5kb3cgZG9jdW1lbnQgU3ltYm9sIFNldCBNYXAgV2Vha1NldCBXZWFrTWFwIFByb3h5IFJlZmxlY3QgUHJvbWlzZSJ9LGE9e2NOOiJudW1iZXIiLHY6W3tiOiJcXGIoMFtiQl1bMDFdKykifSx7YjoiXFxiKDBbb09dWzAtN10rKSJ9LHtiOmUuQ05SfV0scjowfSxvPXtjTjoic3Vic3QiLGI6IlxcJFxceyIsZToiXFx9IixrOnIsYzpbXX0saT17YjoiaHRtbGAiLGU6IiIsc3RhcnRzOntlOiJgIixyRTohMSxjOltlLkJFLG9dLHNMOiJ4bWwifX0sbj17YjoiY3NzYCIsZToiIixzdGFydHM6e2U6ImAiLHJFOiExLGM6W2UuQkUsb10sc0w6ImNzcyJ9fSxzPXtjTjoic3RyaW5nIixiOiJgIixlOiJgIixjOltlLkJFLG9dfTtvLmM9W2UuQVNNLGUuUVNNLGksbixzLGEsZS5STV07dmFyIGM9by5jLmNvbmNhdChbZS5DQkNNLGUuQ0xDTV0pO3JldHVybnthbGlhc2VzOlsianMiLCJqc3giXSxrOnIsYzpbe2NOOiJtZXRhIixyOjEwLGI6L15ccypbJyJddXNlIChzdHJpY3R8YXNtKVsnIl0vfSx7Y046Im1ldGEiLGI6L14jIS8sZTovJC99LGUuQVNNLGUuUVNNLGksbixzLGUuQ0xDTSxlLkNCQ00sYSx7YjovW3ssXVxzKi8scjowLGM6W3tiOnQrIlxccyo6IixyQjohMCxyOjAsYzpbe2NOOiJhdHRyIixiOnQscjowfV19XX0se2I6IigiK2UuUlNSKyJ8XFxiKGNhc2V8cmV0dXJufHRocm93KVxcYilcXHMqIixrOiJyZXR1cm4gdGhyb3cgY2FzZSIsYzpbZS5DTENNLGUuQ0JDTSxlLlJNLHtjTjoiZnVuY3Rpb24iLGI6IihcXCguKj9cXCl8Iit0KyIpXFxzKj0+IixyQjohMCxlOiJcXHMqPT4iLGM6W3tjTjoicGFyYW1zIix2Olt7Yjp0fSx7YjovXChccypcKS99LHtiOi9cKC8sZTovXCkvLGVCOiEwLGVFOiEwLGs6cixjOmN9XX1dfSx7Y046IiIsYjovXHMvLGU6L1xzKi8sc2tpcDohMH0se2I6LzwvLGU6LyhcL1tBLVphLXowLTlcXC5fOi1dK3xbQS1aYS16MC05XFwuXzotXStcLyk+LyxzTDoieG1sIixjOlt7YjovPFtBLVphLXowLTlcXC5fOi1dK1xzKlwvPi8sc2tpcDohMH0se2I6LzxbQS1aYS16MC05XFwuXzotXSsvLGU6LyhcL1tBLVphLXowLTlcXC5fOi1dK3xbQS1aYS16MC05XFwuXzotXStcLyk+Lyxza2lwOiEwLGM6W3tiOi88W0EtWmEtejAtOVxcLl86LV0rXHMqXC8+Lyxza2lwOiEwfSwic2VsZiJdfV19XSxyOjB9LHtjTjoiZnVuY3Rpb24iLGJLOiJmdW5jdGlvbiIsZTovXHsvLGVFOiEwLGM6W2UuaW5oZXJpdChlLlRNLHtiOnR9KSx7Y046InBhcmFtcyIsYjovXCgvLGU6L1wpLyxlQjohMCxlRTohMCxjOmN9XSxpOi9cW3wlL30se2I6L1wkWyguXS99LGUuTUVUSE9EX0dVQVJELHtjTjoiY2xhc3MiLGJLOiJjbGFzcyIsZTovW3s7PV0vLGVFOiEwLGk6L1s6IlxbXF1dLyxjOlt7Yks6ImV4dGVuZHMifSxlLlVUTV19LHtiSzoiY29uc3RydWN0b3IgZ2V0IHNldCIsZTovXHsvLGVFOiEwfV0saTovIyg/ISEpL319KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoImpzb24iLGZ1bmN0aW9uKGUpe3ZhciB0PXtsaXRlcmFsOiJ0cnVlIGZhbHNlIG51bGwifSxyPVtlLlFTTSxlLkNOTV0sYT17ZToiLCIsZVc6ITAsZUU6ITAsYzpyLGs6dH0sbz17YjoieyIsZToifSIsYzpbe2NOOiJhdHRyIixiOi8iLyxlOi8iLyxjOltlLkJFXSxpOiJcXG4ifSxlLmluaGVyaXQoYSx7YjovOi99KV0saToiXFxTIn0saT17YjoiXFxbIixlOiJcXF0iLGM6W2UuaW5oZXJpdChhKV0saToiXFxTIn07cmV0dXJuIHIuc3BsaWNlKHIubGVuZ3RoLDAsbyxpKSx7YzpyLGs6dCxpOiJcXFMifX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgia290bGluIixmdW5jdGlvbihlKXt2YXIgdD17a2V5d29yZDoiYWJzdHJhY3QgYXMgdmFsIHZhciB2YXJhcmcgZ2V0IHNldCBjbGFzcyBvYmplY3Qgb3BlbiBwcml2YXRlIHByb3RlY3RlZCBwdWJsaWMgbm9pbmxpbmUgY3Jvc3NpbmxpbmUgZHluYW1pYyBmaW5hbCBlbnVtIGlmIGVsc2UgZG8gd2hpbGUgZm9yIHdoZW4gdGhyb3cgdHJ5IGNhdGNoIGZpbmFsbHkgaW1wb3J0IHBhY2thZ2UgaXMgaW4gZnVuIG92ZXJyaWRlIGNvbXBhbmlvbiByZWlmaWVkIGlubGluZSBsYXRlaW5pdCBpbml0IGludGVyZmFjZSBhbm5vdGF0aW9uIGRhdGEgc2VhbGVkIGludGVybmFsIGluZml4IG9wZXJhdG9yIG91dCBieSBjb25zdHJ1Y3RvciBzdXBlciB0YWlscmVjIHdoZXJlIGNvbnN0IGlubmVyIHN1c3BlbmQgdHlwZWFsaWFzIGV4dGVybmFsIGV4cGVjdCBhY3R1YWwgdHJhaXQgdm9sYXRpbGUgdHJhbnNpZW50IG5hdGl2ZSBkZWZhdWx0IixidWlsdF9pbjoiQnl0ZSBTaG9ydCBDaGFyIEludCBMb25nIEJvb2xlYW4gRmxvYXQgRG91YmxlIFZvaWQgVW5pdCBOb3RoaW5nIixsaXRlcmFsOiJ0cnVlIGZhbHNlIG51bGwifSxyPXtjTjoic3ltYm9sIixiOmUuVUlSKyJAIn0sYT17Y046InN1YnN0IixiOiJcXCR7IixlOiJ9IixjOltlLkNOTV19LG89e2NOOiJ2YXJpYWJsZSIsYjoiXFwkIitlLlVJUn0saT17Y046InN0cmluZyIsdjpbe2I6JyIiIicsZTonIiIiJyxjOltvLGFdfSx7YjoiJyIsZToiJyIsaTovXG4vLGM6W2UuQkVdfSx7YjonIicsZTonIicsaTovXG4vLGM6W2UuQkUsbyxhXX1dfTthLmMucHVzaChpKTt2YXIgbj17Y046Im1ldGEiLGI6IkAoPzpmaWxlfHByb3BlcnR5fGZpZWxkfGdldHxzZXR8cmVjZWl2ZXJ8cGFyYW18c2V0cGFyYW18ZGVsZWdhdGUpXFxzKjooPzpcXHMqIitlLlVJUisiKT8ifSxzPXtjTjoibWV0YSIsYjoiQCIrZS5VSVIsYzpbe2I6L1woLyxlOi9cKS8sYzpbZS5pbmhlcml0KGkse2NOOiJtZXRhLXN0cmluZyJ9KV19XX0sYz17Y046Im51bWJlciIsYjoiXFxiKDBbYkJdKFswMV0rWzAxX10rWzAxXSt8WzAxXSspfDBbeFhdKFthLWZBLUYwLTldK1thLWZBLUYwLTlfXStbYS1mQS1GMC05XSt8W2EtZkEtRjAtOV0rKXwoKFtcXGRdK1tcXGRfXStbXFxkXSt8W1xcZF0rKShcXC4oW1xcZF0rW1xcZF9dK1tcXGRdK3xbXFxkXSspKT98XFwuKFtcXGRdK1tcXGRfXStbXFxkXSt8W1xcZF0rKSkoW2VFXVstK10/XFxkKyk/KVtsTGZGXT8iLHI6MH0sbD1lLkMoIi9cXCoiLCJcXCovIix7YzpbZS5DQkNNXX0pLE49e3Y6W3tjTjoidHlwZSIsYjplLlVJUn0se2I6L1woLyxlOi9cKS8sYzpbXX1dfSxkPU47cmV0dXJuIGQudlsxXS5jPVtOXSxOLnZbMV0uYz1bZF0se2FsaWFzZXM6WyJrdCJdLGs6dCxjOltlLkMoIi9cXCpcXCoiLCJcXCovIix7cjowLGM6W3tjTjoiZG9jdGFnIixiOiJAW0EtWmEtel0rIn1dfSksZS5DTENNLGwse2NOOiJrZXl3b3JkIixiOi9cYihicmVha3xjb250aW51ZXxyZXR1cm58dGhpcylcYi8sc3RhcnRzOntjOlt7Y046InN5bWJvbCIsYjovQFx3Ky99XX19LHIsbixzLHtjTjoiZnVuY3Rpb24iLGJLOiJmdW4iLGU6IlsoXXwkIixyQjohMCxlRTohMCxrOnQsaTovZnVuXHMrKDwuKj4pP1teXHNcKF0rKFxzK1teXHNcKF0rKVxzKj0vLHI6NSxjOlt7YjplLlVJUisiXFxzKlxcKCIsckI6ITAscjowLGM6W2UuVVRNXX0se2NOOiJ0eXBlIixiOi88LyxlOi8+LyxrOiJyZWlmaWVkIixyOjB9LHtjTjoicGFyYW1zIixiOi9cKC8sZTovXCkvLGVuZHNQYXJlbnQ6ITAsazp0LHI6MCxjOlt7YjovOi8sZTovWz0sXC9dLyxlVzohMCxjOltOLGUuQ0xDTSxsXSxyOjB9LGUuQ0xDTSxsLG4scyxpLGUuQ05NXX0sbF19LHtjTjoiY2xhc3MiLGJLOiJjbGFzcyBpbnRlcmZhY2UgdHJhaXQiLGU6L1s6XHsoXXwkLyxlRTohMCxpOiJleHRlbmRzIGltcGxlbWVudHMiLGM6W3tiSzoicHVibGljIHByb3RlY3RlZCBpbnRlcm5hbCBwcml2YXRlIGNvbnN0cnVjdG9yIn0sZS5VVE0se2NOOiJ0eXBlIixiOi88LyxlOi8+LyxlQjohMCxlRTohMCxyOjB9LHtjTjoidHlwZSIsYjovWyw6XVxzKi8sZTovWzxcKCxdfCQvLGVCOiEwLHJFOiEwfSxuLHNdfSxpLHtjTjoibWV0YSIsYjoiXiMhL3Vzci9iaW4vZW52IixlOiIkIixpOiJcbiJ9LGNdfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgibGVzcyIsZnVuY3Rpb24oZSl7dmFyIHQ9IltcXHctXSsiLHI9IigiK3QrInxAeyIrdCsifSkiLGE9W10sbz1bXSxpPWZ1bmN0aW9uKGUpe3JldHVybntjTjoic3RyaW5nIixiOiJ+PyIrZSsiLio/IitlfX0sbj1mdW5jdGlvbihlLHQscil7cmV0dXJue2NOOmUsYjp0LHI6cn19LHM9e2I6IlxcKCIsZToiXFwpIixjOm8scjowfTtvLnB1c2goZS5DTENNLGUuQ0JDTSxpKCInIiksaSgnIicpLGUuQ1NTTk0se2I6Iih1cmx8ZGF0YS11cmkpXFwoIixzdGFydHM6e2NOOiJzdHJpbmciLGU6IltcXClcXG5dIixlRTohMH19LG4oIm51bWJlciIsIiNbMC05QS1GYS1mXStcXGIiKSxzLG4oInZhcmlhYmxlIiwiQEA/Iit0LDEwKSxuKCJ2YXJpYWJsZSIsIkB7Iit0KyJ9IiksbigiYnVpbHRfaW4iLCJ+P2BbXmBdKj9gIikse2NOOiJhdHRyaWJ1dGUiLGI6dCsiXFxzKjoiLGU6IjoiLHJCOiEwLGVFOiEwfSx7Y046Im1ldGEiLGI6IiFpbXBvcnRhbnQifSk7dmFyIGM9by5jb25jYXQoe2I6InsiLGU6In0iLGM6YX0pLGw9e2JLOiJ3aGVuIixlVzohMCxjOlt7Yks6ImFuZCBub3QifV0uY29uY2F0KG8pfSxOPXtiOnIrIlxccyo6IixyQjohMCxlOiJbO31dIixyOjAsYzpbe2NOOiJhdHRyaWJ1dGUiLGI6cixlOiI6IixlRTohMCxzdGFydHM6e2VXOiEwLGk6Ils8PSRdIixyOjAsYzpvfX1dfSxkPXtjTjoia2V5d29yZCIsYjoiQChpbXBvcnR8bWVkaWF8Y2hhcnNldHxmb250LWZhY2V8KC1bYS16XSstKT9rZXlmcmFtZXN8c3VwcG9ydHN8ZG9jdW1lbnR8bmFtZXNwYWNlfHBhZ2V8dmlld3BvcnR8aG9zdClcXGIiLHN0YXJ0czp7ZToiWzt7fV0iLHJFOiEwLGM6byxyOjB9fSxFPXtjTjoidmFyaWFibGUiLHY6W3tiOiJAIit0KyJcXHMqOiIscjoxNX0se2I6IkAiK3R9XSxzdGFydHM6e2U6Ils7fV0iLHJFOiEwLGM6Y319LHU9e3Y6W3tiOiJbXFwuIzomXFxbPl0iLGU6Ils7e31dIn0se2I6cixlOiJ7In1dLHJCOiEwLHJFOiEwLGk6Ils8PSckXCJdIixyOjAsYzpbZS5DTENNLGUuQ0JDTSxsLG4oImtleXdvcmQiLCJhbGxcXGIiKSxuKCJ2YXJpYWJsZSIsIkB7Iit0KyJ9Iiksbigic2VsZWN0b3ItdGFnIixyKyIlPyIsMCksbigic2VsZWN0b3ItaWQiLCIjIityKSxuKCJzZWxlY3Rvci1jbGFzcyIsIlxcLiIrciwwKSxuKCJzZWxlY3Rvci10YWciLCImIiwwKSx7Y046InNlbGVjdG9yLWF0dHIiLGI6IlxcWyIsZToiXFxdIn0se2NOOiJzZWxlY3Rvci1wc2V1ZG8iLGI6LzooOik/W2EtekEtWjAtOVxfXC1cK1woXCkiJy5dKy99LHtiOiJcXCgiLGU6IlxcKSIsYzpjfSx7YjoiIWltcG9ydGFudCJ9XX07cmV0dXJuIGEucHVzaChlLkNMQ00sZS5DQkNNLGQsRSxOLHUpLHtjSTohMCxpOiJbPT4nLzwoJFwiXSIsYzphfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgibWFrZWZpbGUiLGZ1bmN0aW9uKGUpe3ZhciB0PXtjTjoidmFyaWFibGUiLHY6W3tiOiJcXCRcXCgiK2UuVUlSKyJcXCkiLGM6W2UuQkVdfSx7YjovXCRbQCU8P1xeXCtcKl0vfV19LHI9e2NOOiJzdHJpbmciLGI6LyIvLGU6LyIvLGM6W2UuQkUsdF19LGE9e2NOOiJ2YXJpYWJsZSIsYjovXCRcKFtcdy1dK1xzLyxlOi9cKS8sazp7YnVpbHRfaW46InN1YnN0IHBhdHN1YnN0IHN0cmlwIGZpbmRzdHJpbmcgZmlsdGVyIGZpbHRlci1vdXQgc29ydCB3b3JkIHdvcmRsaXN0IGZpcnN0d29yZCBsYXN0d29yZCBkaXIgbm90ZGlyIHN1ZmZpeCBiYXNlbmFtZSBhZGRzdWZmaXggYWRkcHJlZml4IGpvaW4gd2lsZGNhcmQgcmVhbHBhdGggYWJzcGF0aCBlcnJvciB3YXJuaW5nIHNoZWxsIG9yaWdpbiBmbGF2b3IgZm9yZWFjaCBpZiBvciBhbmQgY2FsbCBldmFsIGZpbGUgdmFsdWUifSxjOlt0XX0sbz17YjoiXiIrZS5VSVIrIlxccypbOis/XT89IixpOiJcXG4iLHJCOiEwLGM6W3tiOiJeIitlLlVJUixlOiJbOis/XT89IixlRTohMH1dfSxpPXtjTjoic2VjdGlvbiIsYjovXlteXHNdKzovLGU6LyQvLGM6W3RdfTtyZXR1cm57YWxpYXNlczpbIm1rIiwibWFrIl0sazoiZGVmaW5lIGVuZGVmIHVuZGVmaW5lIGlmZGVmIGlmbmRlZiBpZmVxIGlmbmVxIGVsc2UgZW5kaWYgaW5jbHVkZSAtaW5jbHVkZSBzaW5jbHVkZSBvdmVycmlkZSBleHBvcnQgdW5leHBvcnQgcHJpdmF0ZSB2cGF0aCIsbDovW1x3LV0rLyxjOltlLkhDTSx0LHIsYSxvLHtjTjoibWV0YSIsYjovXlwuUEhPTlk6LyxlOi8kLyxrOnsibWV0YS1rZXl3b3JkIjoiLlBIT05ZIn0sbDovW1wuXHddKy99LGldfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgieG1sIixmdW5jdGlvbihlKXt2YXIgdD17ZVc6ITAsaTovPC8scjowLGM6W3tjTjoiYXR0ciIsYjoiW0EtWmEtejAtOVxcLl86LV0rIixyOjB9LHtiOi89XHMqLyxyOjAsYzpbe2NOOiJzdHJpbmciLGVuZHNQYXJlbnQ6ITAsdjpbe2I6LyIvLGU6LyIvfSx7YjovJy8sZTovJy99LHtiOi9bXlxzIic9PD5gXSsvfV19XX1dfTtyZXR1cm57YWxpYXNlczpbImh0bWwiLCJ4aHRtbCIsInJzcyIsImF0b20iLCJ4amIiLCJ4c2QiLCJ4c2wiLCJwbGlzdCIsIndzZiJdLGNJOiEwLGM6W3tjTjoibWV0YSIsYjoiPCFET0NUWVBFIixlOiI+IixyOjEwLGM6W3tiOiJcXFsiLGU6IlxcXSJ9XX0sZS5DKCJceDNjIS0tIiwiLS1ceDNlIix7cjoxMH0pLHtiOiI8XFwhXFxbQ0RBVEFcXFsiLGU6IlxcXVxcXT4iLHI6MTB9LHtjTjoibWV0YSIsYjovPFw/eG1sLyxlOi9cPz4vLHI6MTB9LHtiOi88XD8ocGhwKT8vLGU6L1w/Pi8sc0w6InBocCIsYzpbe2I6Ii9cXCoiLGU6IlxcKi8iLHNraXA6ITB9LHtiOidiIicsZTonIicsc2tpcDohMH0se2I6ImInIixlOiInIixza2lwOiEwfSxlLmluaGVyaXQoZS5BU00se2k6bnVsbCxjTjpudWxsLGM6bnVsbCxza2lwOiEwfSksZS5pbmhlcml0KGUuUVNNLHtpOm51bGwsY046bnVsbCxjOm51bGwsc2tpcDohMH0pXX0se2NOOiJ0YWciLGI6IjxzdHlsZSg/PVxcc3w+fCQpIixlOiI+IixrOntuYW1lOiJzdHlsZSJ9LGM6W3RdLHN0YXJ0czp7ZToiPC9zdHlsZT4iLHJFOiEwLHNMOlsiY3NzIiwieG1sIl19fSx7Y046InRhZyIsYjoiPHNjcmlwdCg/PVxcc3w+fCQpIixlOiI+IixrOntuYW1lOiJzY3JpcHQifSxjOlt0XSxzdGFydHM6e2U6IjxcL3NjcmlwdD4iLHJFOiEwLHNMOlsiYWN0aW9uc2NyaXB0IiwiamF2YXNjcmlwdCIsImhhbmRsZWJhcnMiLCJ4bWwiLCJ2YnNjcmlwdCJdfX0se2NOOiJ0YWciLGI6IjwvPyIsZToiLz8+IixjOlt7Y046Im5hbWUiLGI6L1teXC8+PFxzXSsvLHI6MH0sdF19XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoIm5naW54IixmdW5jdGlvbihlKXt2YXIgdD17Y046InZhcmlhYmxlIix2Olt7YjovXCRcZCsvfSx7YjovXCRcey8sZTovfS99LHtiOiJbXFwkXFxAXSIrZS5VSVJ9XX0scj17ZVc6ITAsbDoiW2Etei9fXSsiLGs6e2xpdGVyYWw6Im9uIG9mZiB5ZXMgbm8gdHJ1ZSBmYWxzZSBub25lIGJsb2NrZWQgZGVidWcgaW5mbyBub3RpY2Ugd2FybiBlcnJvciBjcml0IHNlbGVjdCBicmVhayBsYXN0IHBlcm1hbmVudCByZWRpcmVjdCBrcXVldWUgcnRzaWcgZXBvbGwgcG9sbCAvZGV2L3BvbGwifSxyOjAsaToiPT4iLGM6W2UuSENNLHtjTjoic3RyaW5nIixjOltlLkJFLHRdLHY6W3tiOi8iLyxlOi8iL30se2I6LycvLGU6LycvfV19LHtiOiIoW2Etel0rKTovIixlOiJcXHMiLGVXOiEwLGVFOiEwLGM6W3RdfSx7Y046InJlZ2V4cCIsYzpbZS5CRSx0XSx2Olt7YjoiXFxzXFxeIixlOiJcXHN8e3w7IixyRTohMH0se2I6In5cXCo/XFxzKyIsZToiXFxzfHt8OyIsckU6ITB9LHtiOiJcXCooXFwuW2EtelxcLV0rKSsifSx7YjoiKFthLXpcXC1dK1xcLikrXFwqIn1dfSx7Y046Im51bWJlciIsYjoiXFxiXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM30oOlxcZHsxLDV9KT9cXGIifSx7Y046Im51bWJlciIsYjoiXFxiXFxkK1trS21NZ0dkc2hkd3ldKlxcYiIscjowfSx0XX07cmV0dXJue2FsaWFzZXM6WyJuZ2lueGNvbmYiXSxjOltlLkhDTSx7YjplLlVJUisiXFxzK3siLHJCOiEwLGU6InsiLGM6W3tjTjoic2VjdGlvbiIsYjplLlVJUn1dLHI6MH0se2I6ZS5VSVIrIlxccyIsZToiO3x7IixyQjohMCxjOlt7Y046ImF0dHJpYnV0ZSIsYjplLlVJUixzdGFydHM6cn1dLHI6MH1dLGk6IlteXFxzXFx9XSJ9fSksby5yZWdpc3Rlckxhbmd1YWdlKCJwZXJsIixmdW5jdGlvbihlKXt2YXIgdD0iZ2V0cHdlbnQgZ2V0c2VydmVudCBxdW90ZW1ldGEgbXNncmN2IHNjYWxhciBraWxsIGRibWNsb3NlIHVuZGVmIGxjIG1hIHN5c3dyaXRlIHRyIHNlbmQgdW1hc2sgc3lzb3BlbiBzaG13cml0ZSB2ZWMgcXggdXRpbWUgbG9jYWwgb2N0IHNlbWN0bCBsb2NhbHRpbWUgcmVhZHBpcGUgZG8gcmV0dXJuIGZvcm1hdCByZWFkIHNwcmludGYgZGJtb3BlbiBwb3AgZ2V0cGdycCBub3QgZ2V0cHduYW0gcmV3aW5kZGlyIHFxZmlsZW5vIHF3IGVuZHByb3RvZW50IHdhaXQgc2V0aG9zdGVudCBibGVzcyBzfDAgb3BlbmRpciBjb250aW51ZSBlYWNoIHNsZWVwIGVuZGdyZW50IHNodXRkb3duIGR1bXAgY2hvbXAgY29ubmVjdCBnZXRzb2NrbmFtZSBkaWUgc29ja2V0cGFpciBjbG9zZSBmbG9jayBleGlzdHMgaW5kZXggc2htZ2V0c3ViIGZvciBlbmRwd2VudCByZWRvIGxzdGF0IG1zZ2N0bCBzZXRwZ3JwIGFicyBleGl0IHNlbGVjdCBwcmludCByZWYgZ2V0aG9zdGJ5YWRkciB1bnNoaWZ0IGZjbnRsIHN5c2NhbGwgZ290byBnZXRuZXRieWFkZHIgam9pbiBnbXRpbWUgc3ltbGluayBzZW1nZXQgc3BsaWNlIHh8MCBnZXRwZWVybmFtZSByZWN2IGxvZyBzZXRzb2Nrb3B0IGNvcyBsYXN0IHJldmVyc2UgZ2V0aG9zdGJ5bmFtZSBnZXRncm5hbSBzdHVkeSBmb3JtbGluZSBlbmRob3N0ZW50IHRpbWVzIGNob3AgbGVuZ3RoIGdldGhvc3RlbnQgZ2V0bmV0ZW50IHBhY2sgZ2V0cHJvdG9lbnQgZ2V0c2VydmJ5bmFtZSByYW5kIG1rZGlyIHBvcyBjaG1vZCB5fDAgc3Vic3RyIGVuZG5ldGVudCBwcmludGYgbmV4dCBvcGVuIG1zZ3NuZCByZWFkZGlyIHVzZSB1bmxpbmsgZ2V0c29ja29wdCBnZXRwcmlvcml0eSByaW5kZXggd2FudGFycmF5IGhleCBzeXN0ZW0gZ2V0c2VydmJ5cG9ydCBlbmRzZXJ2ZW50IGludCBjaHIgdW50aWUgcm1kaXIgcHJvdG90eXBlIHRlbGwgbGlzdGVuIGZvcmsgc2htcmVhZCB1Y2ZpcnN0IHNldHByb3RvZW50IGVsc2Ugc3lzc2VlayBsaW5rIGdldGdyZ2lkIHNobWN0bCB3YWl0cGlkIHVucGFjayBnZXRuZXRieW5hbWUgcmVzZXQgY2hkaXIgZ3JlcCBzcGxpdCByZXF1aXJlIGNhbGxlciBsY2ZpcnN0IHVudGlsIHdhcm4gd2hpbGUgdmFsdWVzIHNoaWZ0IHRlbGxkaXIgZ2V0cHd1aWQgbXkgZ2V0cHJvdG9ieW51bWJlciBkZWxldGUgYW5kIHNvcnQgdWMgZGVmaW5lZCBzcmFuZCBhY2NlcHQgcGFja2FnZSBzZWVrZGlyIGdldHByb3RvYnluYW1lIHNlbW9wIG91ciByZW5hbWUgc2VlayBpZiBxfDAgY2hyb290IHN5c3JlYWQgc2V0cHdlbnQgbm8gY3J5cHQgZ2V0YyBjaG93biBzcXJ0IHdyaXRlIHNldG5ldGVudCBzZXRwcmlvcml0eSBmb3JlYWNoIHRpZSBzaW4gbXNnZ2V0IG1hcCBzdGF0IGdldGxvZ2luIHVubGVzcyBlbHNpZiB0cnVuY2F0ZSBleGVjIGtleXMgZ2xvYiB0aWVkIGNsb3NlZGlyaW9jdGwgc29ja2V0IHJlYWRsaW5rIGV2YWwgeG9yIHJlYWRsaW5lIGJpbm1vZGUgc2V0c2VydmVudCBlb2Ygb3JkIGJpbmQgYWxhcm0gcGlwZSBhdGFuMiBnZXRncmVudCBleHAgdGltZSBwdXNoIHNldGdyZW50IGd0IGx0IG9yIG5lIG18MCBicmVhayBnaXZlbiBzYXkgc3RhdGUgd2hlbiIscj17Y046InN1YnN0IixiOiJbJEBdXFx7IixlOiJcXH0iLGs6dH0sYT17YjoiLT57IixlOiJ9In0sbz17djpbe2I6L1wkXGQvfSx7YjovW1wkJUBdKFxeXHdcYnwjXHcrKDo6XHcrKSp8e1x3K318XHcrKDo6XHcqKSopL30se2I6L1tcJCVAXVteXHNcd3tdLyxyOjB9XX0saT1bZS5CRSxyLG9dLG49W28sZS5IQ00sZS5DKCJeXFw9XFx3IiwiXFw9Y3V0Iix7ZVc6ITB9KSxhLHtjTjoic3RyaW5nIixjOmksdjpbe2I6InFbcXd4cl0/XFxzKlxcKCIsZToiXFwpIixyOjV9LHtiOiJxW3F3eHJdP1xccypcXFsiLGU6IlxcXSIscjo1fSx7YjoicVtxd3hyXT9cXHMqXFx7IixlOiJcXH0iLHI6NX0se2I6InFbcXd4cl0/XFxzKlxcfCIsZToiXFx8IixyOjV9LHtiOiJxW3F3eHJdP1xccypcXDwiLGU6IlxcPiIscjo1fSx7YjoicXdcXHMrcSIsZToicSIscjo1fSx7YjoiJyIsZToiJyIsYzpbZS5CRV19LHtiOiciJyxlOiciJ30se2I6ImAiLGU6ImAiLGM6W2UuQkVdfSx7Yjoie1xcdyt9IixjOltdLHI6MH0se2I6Ii0/XFx3K1xccypcXD1cXD4iLGM6W10scjowfV19LHtjTjoibnVtYmVyIixiOiIoXFxiMFswLTdfXSspfChcXGIweFswLTlhLWZBLUZfXSspfChcXGJbMS05XVswLTlfXSooXFwuWzAtOV9dKyk/KXxbMF9dXFxiIixyOjB9LHtiOiIoXFwvXFwvfCIrZS5SU1IrInxcXGIoc3BsaXR8cmV0dXJufHByaW50fHJldmVyc2V8Z3JlcClcXGIpXFxzKiIsazoic3BsaXQgcmV0dXJuIHByaW50IHJldmVyc2UgZ3JlcCIscjowLGM6W2UuSENNLHtjTjoicmVnZXhwIixiOiIoc3x0cnx5KS8oXFxcXC58W14vXSkqLyhcXFxcLnxbXi9dKSovW2Etel0qIixyOjEwfSx7Y046InJlZ2V4cCIsYjoiKG18cXIpPy8iLGU6Ii9bYS16XSoiLGM6W2UuQkVdLHI6MH1dfSx7Y046ImZ1bmN0aW9uIixiSzoic3ViIixlOiIoXFxzKlxcKC4qP1xcKSk/Wzt7XSIsZUU6ITAscjo1LGM6W2UuVE1dfSx7YjoiLVxcd1xcYiIscjowfSx7YjoiXl9fREFUQV9fJCIsZToiXl9fRU5EX18kIixzTDoibW9qb2xpY2lvdXMiLGM6W3tiOiJeQEAuKiIsZToiJCIsY046ImNvbW1lbnQifV19XTtyZXR1cm4gci5jPW4se2FsaWFzZXM6WyJwbCIsInBtIl0sbDovW1x3XC5dKy8sazp0LGM6YS5jPW59fSksby5yZWdpc3Rlckxhbmd1YWdlKCJwZ3NxbCIsZnVuY3Rpb24oZSl7dmFyIHQ9ZS5DKCItLSIsIiQiKSxyPSJCSUdJTlQgSU5UOCBCSUdTRVJJQUwgU0VSSUFMOCBCSVQgVkFSWUlORyBWQVJCSVQgQk9PTEVBTiBCT09MIEJPWCBCWVRFQSBDSEFSQUNURVIgQ0hBUiBWQVJDSEFSIENJRFIgQ0lSQ0xFIERBVEUgRE9VQkxFIFBSRUNJU0lPTiBGTE9BVDggRkxPQVQgSU5FVCBJTlRFR0VSIElOVCBJTlQ0IElOVEVSVkFMIEpTT04gSlNPTkIgTElORSBMU0VHfDEwIE1BQ0FERFIgTUFDQUREUjggTU9ORVkgTlVNRVJJQyBERUMgREVDSU1BTCBQQVRIIFBPSU5UIFBPTFlHT04gUkVBTCBGTE9BVDQgU01BTExJTlQgSU5UMiBTTUFMTFNFUklBTHwxMCBTRVJJQUwyfDEwIFNFUklBTHwxMCBTRVJJQUw0fDEwIFRFWFQgVElNRSBaT05FIFRJTUVUWnwxMCBUSU1FU1RBTVAgVElNRVNUQU1QVFp8MTAgVFNRVUVSWXwxMCBUU1ZFQ1RPUnwxMCBUWElEX1NOQVBTSE9UfDEwIFVVSUQgWE1MIE5BVElPTkFMIE5DSEFSIElOVDRSQU5HRXwxMCBJTlQ4UkFOR0V8MTAgTlVNUkFOR0V8MTAgVFNSQU5HRXwxMCBUU1RaUkFOR0V8MTAgREFURVJBTkdFfDEwIEFOWUVMRU1FTlQgQU5ZQVJSQVkgQU5ZTk9OQVJSQVkgQU5ZRU5VTSBBTllSQU5HRSBDU1RSSU5HIElOVEVSTkFMIFJFQ09SRCBQR19ERExfQ09NTUFORCBWT0lEIFVOS05PV04gT1BBUVVFIFJFRkNVUlNPUiBOQU1FIE9JRCBSRUdQUk9DfDEwIFJFR1BST0NFRFVSRXwxMCBSRUdPUEVSfDEwIFJFR09QRVJBVE9SfDEwIFJFR0NMQVNTfDEwIFJFR1RZUEV8MTAgUkVHUk9MRXwxMCBSRUdOQU1FU1BBQ0V8MTAgUkVHQ09ORklHfDEwIFJFR0RJQ1RJT05BUll8MTAgIixhPXIudHJpbSgpLnNwbGl0KCIgIikubWFwKGZ1bmN0aW9uKGUpe3JldHVybiBlLnNwbGl0KCJ8IilbMF19KS5qb2luKCJ8Iiksbz0iQVJSQVlfQUdHIEFWRyBCSVRfQU5EIEJJVF9PUiBCT09MX0FORCBCT09MX09SIENPVU5UIEVWRVJZIEpTT05fQUdHIEpTT05CX0FHRyBKU09OX09CSkVDVF9BR0cgSlNPTkJfT0JKRUNUX0FHRyBNQVggTUlOIE1PREUgU1RSSU5HX0FHRyBTVU0gWE1MQUdHIENPUlIgQ09WQVJfUE9QIENPVkFSX1NBTVAgUkVHUl9BVkdYIFJFR1JfQVZHWSBSRUdSX0NPVU5UIFJFR1JfSU5URVJDRVBUIFJFR1JfUjIgUkVHUl9TTE9QRSBSRUdSX1NYWCBSRUdSX1NYWSBSRUdSX1NZWSBTVERERVYgU1REREVWX1BPUCBTVERERVZfU0FNUCBWQVJJQU5DRSBWQVJfUE9QIFZBUl9TQU1QIFBFUkNFTlRJTEVfQ09OVCBQRVJDRU5USUxFX0RJU0MgUk9XX05VTUJFUiBSQU5LIERFTlNFX1JBTksgUEVSQ0VOVF9SQU5LIENVTUVfRElTVCBOVElMRSBMQUcgTEVBRCBGSVJTVF9WQUxVRSBMQVNUX1ZBTFVFIE5USF9WQUxVRSBOVU1fTk9OTlVMTFMgTlVNX05VTExTIEFCUyBDQlJUIENFSUwgQ0VJTElORyBERUdSRUVTIERJViBFWFAgRkxPT1IgTE4gTE9HIE1PRCBQSSBQT1dFUiBSQURJQU5TIFJPVU5EIFNDQUxFIFNJR04gU1FSVCBUUlVOQyBXSURUSF9CVUNLRVQgUkFORE9NIFNFVFNFRUQgQUNPUyBBQ09TRCBBU0lOIEFTSU5EIEFUQU4gQVRBTkQgQVRBTjIgQVRBTjJEIENPUyBDT1NEIENPVCBDT1REIFNJTiBTSU5EIFRBTiBUQU5EIEJJVF9MRU5HVEggQ0hBUl9MRU5HVEggQ0hBUkFDVEVSX0xFTkdUSCBMT1dFUiBPQ1RFVF9MRU5HVEggT1ZFUkxBWSBQT1NJVElPTiBTVUJTVFJJTkcgVFJFQVQgVFJJTSBVUFBFUiBBU0NJSSBCVFJJTSBDSFIgQ09OQ0FUIENPTkNBVF9XUyBDT05WRVJUIENPTlZFUlRfRlJPTSBDT05WRVJUX1RPIERFQ09ERSBFTkNPREUgSU5JVENBUExFRlQgTEVOR1RIIExQQUQgTFRSSU0gTUQ1IFBBUlNFX0lERU5UIFBHX0NMSUVOVF9FTkNPRElORyBRVU9URV9JREVOVHwxMCBRVU9URV9MSVRFUkFMfDEwIFFVT1RFX05VTExBQkxFfDEwIFJFR0VYUF9NQVRDSCBSRUdFWFBfTUFUQ0hFUyBSRUdFWFBfUkVQTEFDRSBSRUdFWFBfU1BMSVRfVE9fQVJSQVkgUkVHRVhQX1NQTElUX1RPX1RBQkxFIFJFUEVBVCBSRVBMQUNFIFJFVkVSU0UgUklHSFQgUlBBRCBSVFJJTSBTUExJVF9QQVJUIFNUUlBPUyBTVUJTVFIgVE9fQVNDSUkgVE9fSEVYIFRSQU5TTEFURSBPQ1RFVF9MRU5HVEggR0VUX0JJVCBHRVRfQllURSBTRVRfQklUIFNFVF9CWVRFIFRPX0NIQVIgVE9fREFURSBUT19OVU1CRVIgVE9fVElNRVNUQU1QIEFHRSBDTE9DS19USU1FU1RBTVB8MTAgREFURV9QQVJUIERBVEVfVFJVTkMgSVNGSU5JVEUgSlVTVElGWV9EQVlTIEpVU1RJRllfSE9VUlMgSlVTVElGWV9JTlRFUlZBTCBNQUtFX0RBVEUgTUFLRV9JTlRFUlZBTHwxMCBNQUtFX1RJTUUgTUFLRV9USU1FU1RBTVB8MTAgTUFLRV9USU1FU1RBTVBUWnwxMCBOT1cgU1RBVEVNRU5UX1RJTUVTVEFNUHwxMCBUSU1FT0ZEQVkgVFJBTlNBQ1RJT05fVElNRVNUQU1QfDEwIEVOVU1fRklSU1QgRU5VTV9MQVNUIEVOVU1fUkFOR0UgQVJFQSBDRU5URVIgRElBTUVURVIgSEVJR0hUIElTQ0xPU0VEIElTT1BFTiBOUE9JTlRTIFBDTE9TRSBQT1BFTiBSQURJVVMgV0lEVEggQk9YIEJPVU5EX0JPWCBDSVJDTEUgTElORSBMU0VHIFBBVEggUE9MWUdPTiBBQkJSRVYgQlJPQURDQVNUIEhPU1QgSE9TVE1BU0sgTUFTS0xFTiBORVRNQVNLIE5FVFdPUksgU0VUX01BU0tMRU4gVEVYVCBJTkVUX1NBTUVfRkFNSUxZSU5FVF9NRVJHRSBNQUNBRERSOF9TRVQ3QklUIEFSUkFZX1RPX1RTVkVDVE9SIEdFVF9DVVJSRU5UX1RTX0NPTkZJRyBOVU1OT0RFIFBMQUlOVE9fVFNRVUVSWSBQSFJBU0VUT19UU1FVRVJZIFdFQlNFQVJDSF9UT19UU1FVRVJZIFFVRVJZVFJFRSBTRVRXRUlHSFQgU1RSSVAgVE9fVFNRVUVSWSBUT19UU1ZFQ1RPUiBKU09OX1RPX1RTVkVDVE9SIEpTT05CX1RPX1RTVkVDVE9SIFRTX0RFTEVURSBUU19GSUxURVIgVFNfSEVBRExJTkUgVFNfUkFOSyBUU19SQU5LX0NEIFRTX1JFV1JJVEUgVFNRVUVSWV9QSFJBU0UgVFNWRUNUT1JfVE9fQVJSQVkgVFNWRUNUT1JfVVBEQVRFX1RSSUdHRVIgVFNWRUNUT1JfVVBEQVRFX1RSSUdHRVJfQ09MVU1OIFhNTENPTU1FTlQgWE1MQ09OQ0FUIFhNTEVMRU1FTlQgWE1MRk9SRVNUIFhNTFBJIFhNTFJPT1QgWE1MRVhJU1RTIFhNTF9JU19XRUxMX0ZPUk1FRCBYTUxfSVNfV0VMTF9GT1JNRURfRE9DVU1FTlQgWE1MX0lTX1dFTExfRk9STUVEX0NPTlRFTlQgWFBBVEggWFBBVEhfRVhJU1RTIFhNTFRBQkxFIFhNTE5BTUVTUEFDRVMgVEFCTEVfVE9fWE1MIFRBQkxFX1RPX1hNTFNDSEVNQSBUQUJMRV9UT19YTUxfQU5EX1hNTFNDSEVNQSBRVUVSWV9UT19YTUwgUVVFUllfVE9fWE1MU0NIRU1BIFFVRVJZX1RPX1hNTF9BTkRfWE1MU0NIRU1BIENVUlNPUl9UT19YTUwgQ1VSU09SX1RPX1hNTFNDSEVNQSBTQ0hFTUFfVE9fWE1MIFNDSEVNQV9UT19YTUxTQ0hFTUEgU0NIRU1BX1RPX1hNTF9BTkRfWE1MU0NIRU1BIERBVEFCQVNFX1RPX1hNTCBEQVRBQkFTRV9UT19YTUxTQ0hFTUEgREFUQUJBU0VfVE9fWE1MX0FORF9YTUxTQ0hFTUEgWE1MQVRUUklCVVRFUyBUT19KU09OIFRPX0pTT05CIEFSUkFZX1RPX0pTT04gUk9XX1RPX0pTT04gSlNPTl9CVUlMRF9BUlJBWSBKU09OQl9CVUlMRF9BUlJBWSBKU09OX0JVSUxEX09CSkVDVCBKU09OQl9CVUlMRF9PQkpFQ1QgSlNPTl9PQkpFQ1QgSlNPTkJfT0JKRUNUIEpTT05fQVJSQVlfTEVOR1RIIEpTT05CX0FSUkFZX0xFTkdUSCBKU09OX0VBQ0ggSlNPTkJfRUFDSCBKU09OX0VBQ0hfVEVYVCBKU09OQl9FQUNIX1RFWFQgSlNPTl9FWFRSQUNUX1BBVEggSlNPTkJfRVhUUkFDVF9QQVRIIEpTT05fT0JKRUNUX0tFWVMgSlNPTkJfT0JKRUNUX0tFWVMgSlNPTl9QT1BVTEFURV9SRUNPUkQgSlNPTkJfUE9QVUxBVEVfUkVDT1JEIEpTT05fUE9QVUxBVEVfUkVDT1JEU0VUIEpTT05CX1BPUFVMQVRFX1JFQ09SRFNFVCBKU09OX0FSUkFZX0VMRU1FTlRTIEpTT05CX0FSUkFZX0VMRU1FTlRTIEpTT05fQVJSQVlfRUxFTUVOVFNfVEVYVCBKU09OQl9BUlJBWV9FTEVNRU5UU19URVhUIEpTT05fVFlQRU9GIEpTT05CX1RZUEVPRiBKU09OX1RPX1JFQ09SRCBKU09OQl9UT19SRUNPUkQgSlNPTl9UT19SRUNPUkRTRVQgSlNPTkJfVE9fUkVDT1JEU0VUIEpTT05fU1RSSVBfTlVMTFMgSlNPTkJfU1RSSVBfTlVMTFMgSlNPTkJfU0VUIEpTT05CX0lOU0VSVCBKU09OQl9QUkVUVFkgQ1VSUlZBTCBMQVNUVkFMIE5FWFRWQUwgU0VUVkFMIENPQUxFU0NFIE5VTExJRiBHUkVBVEVTVCBMRUFTVCBBUlJBWV9BUFBFTkQgQVJSQVlfQ0FUIEFSUkFZX05ESU1TIEFSUkFZX0RJTVMgQVJSQVlfRklMTCBBUlJBWV9MRU5HVEggQVJSQVlfTE9XRVIgQVJSQVlfUE9TSVRJT04gQVJSQVlfUE9TSVRJT05TIEFSUkFZX1BSRVBFTkQgQVJSQVlfUkVNT1ZFIEFSUkFZX1JFUExBQ0UgQVJSQVlfVE9fU1RSSU5HIEFSUkFZX1VQUEVSIENBUkRJTkFMSVRZIFNUUklOR19UT19BUlJBWSBVTk5FU1QgSVNFTVBUWSBMT1dFUl9JTkMgVVBQRVJfSU5DIExPV0VSX0lORiBVUFBFUl9JTkYgUkFOR0VfTUVSR0UgR0VORVJBVEVfU0VSSUVTIEdFTkVSQVRFX1NVQlNDUklQVFMgQ1VSUkVOVF9EQVRBQkFTRSBDVVJSRU5UX1FVRVJZIENVUlJFTlRfU0NIRU1BfDEwIENVUlJFTlRfU0NIRU1BU3wxMCBJTkVUX0NMSUVOVF9BRERSIElORVRfQ0xJRU5UX1BPUlQgSU5FVF9TRVJWRVJfQUREUiBJTkVUX1NFUlZFUl9QT1JUIFJPV19TRUNVUklUWV9BQ1RJVkUgRk9STUFUX1RZUEUgVE9fUkVHQ0xBU1MgVE9fUkVHUFJPQyBUT19SRUdQUk9DRURVUkUgVE9fUkVHT1BFUiBUT19SRUdPUEVSQVRPUiBUT19SRUdUWVBFIFRPX1JFR05BTUVTUEFDRSBUT19SRUdST0xFIENPTF9ERVNDUklQVElPTiBPQkpfREVTQ1JJUFRJT04gU0hPQkpfREVTQ1JJUFRJT04gVFhJRF9DVVJSRU5UIFRYSURfQ1VSUkVOVF9JRl9BU1NJR05FRCBUWElEX0NVUlJFTlRfU05BUFNIT1QgVFhJRF9TTkFQU0hPVF9YSVAgVFhJRF9TTkFQU0hPVF9YTUFYIFRYSURfU05BUFNIT1RfWE1JTiBUWElEX1ZJU0lCTEVfSU5fU05BUFNIT1QgVFhJRF9TVEFUVVMgQ1VSUkVOVF9TRVRUSU5HIFNFVF9DT05GSUcgQlJJTl9TVU1NQVJJWkVfTkVXX1ZBTFVFUyBCUklOX1NVTU1BUklaRV9SQU5HRSBCUklOX0RFU1VNTUFSSVpFX1JBTkdFIEdJTl9DTEVBTl9QRU5ESU5HX0xJU1QgU1VQUFJFU1NfUkVEVU5EQU5UX1VQREFURVNfVFJJR0dFUiBMT19GUk9NX0JZVEVBIExPX1BVVCBMT19HRVQgTE9fQ1JFQVQgTE9fQ1JFQVRFIExPX1VOTElOSyBMT19JTVBPUlQgTE9fRVhQT1JUIExPUkVBRCBMT1dSSVRFIEdST1VQSU5HIENBU1QgIi50cmltKCkuc3BsaXQoIiAiKS5tYXAoZnVuY3Rpb24oZSl7cmV0dXJuIGUuc3BsaXQoInwiKVswXX0pLmpvaW4oInwiKTtyZXR1cm57YWxpYXNlczpbInBvc3RncmVzIiwicG9zdGdyZXNxbCJdLGNJOiEwLGs6e2tleXdvcmQ6IkFCT1JUIEFMVEVSIEFOQUxZWkUgQkVHSU4gQ0FMTCBDSEVDS1BPSU5UfDEwIENMT1NFIENMVVNURVIgQ09NTUVOVCBDT01NSVQgQ09QWSBDUkVBVEUgREVBTExPQ0FURSBERUNMQVJFIERFTEVURSBESVNDQVJEIERPIERST1AgRU5EIEVYRUNVVEUgRVhQTEFJTiBGRVRDSCBHUkFOVCBJTVBPUlQgSU5TRVJUIExJU1RFTiBMT0FEIExPQ0sgTU9WRSBOT1RJRlkgUFJFUEFSRSBSRUFTU0lHTnwxMCBSRUZSRVNIIFJFSU5ERVggUkVMRUFTRSBSRVNFVCBSRVZPS0UgUk9MTEJBQ0sgU0FWRVBPSU5UIFNFQ1VSSVRZIFNFTEVDVCBTRVQgU0hPVyBTVEFSVCBUUlVOQ0FURSBVTkxJU1RFTnwxMCBVUERBVEUgVkFDVVVNfDEwIFZBTFVFUyBBR0dSRUdBVEUgQ09MTEFUSU9OIENPTlZFUlNJT058MTAgREFUQUJBU0UgREVGQVVMVCBQUklWSUxFR0VTIERPTUFJTiBUUklHR0VSIEVYVEVOU0lPTiBGT1JFSUdOIFdSQVBQRVJ8MTAgVEFCTEUgRlVOQ1RJT04gR1JPVVAgTEFOR1VBR0UgTEFSR0UgT0JKRUNUIE1BVEVSSUFMSVpFRCBWSUVXIE9QRVJBVE9SIENMQVNTIEZBTUlMWSBQT0xJQ1kgUFVCTElDQVRJT058MTAgUk9MRSBSVUxFIFNDSEVNQSBTRVFVRU5DRSBTRVJWRVIgU1RBVElTVElDUyBTVUJTQ1JJUFRJT04gU1lTVEVNIFRBQkxFU1BBQ0UgQ09ORklHVVJBVElPTiBESUNUSU9OQVJZIFBBUlNFUiBURU1QTEFURSBUWVBFIFVTRVIgTUFQUElORyBQUkVQQVJFRCBBQ0NFU1MgTUVUSE9EIENBU1QgQVMgVFJBTlNGT1JNIFRSQU5TQUNUSU9OIE9XTkVEIFRPIElOVE8gU0VTU0lPTiBBVVRIT1JJWkFUSU9OIElOREVYIFBST0NFRFVSRSBBU1NFUlRJT04gQUxMIEFOQUxZU0UgQU5EIEFOWSBBUlJBWSBBU0MgQVNZTU1FVFJJQ3wxMCBCT1RIIENBU0UgQ0hFQ0sgQ09MTEFURSBDT0xVTU4gQ09OQ1VSUkVOVExZfDEwIENPTlNUUkFJTlQgQ1JPU1MgREVGRVJSQUJMRSBSQU5HRSBERVNDIERJU1RJTkNUIEVMU0UgRVhDRVBUIEZPUiBGUkVFWkV8MTAgRlJPTSBGVUxMIEhBVklORyBJTElLRSBJTiBJTklUSUFMTFkgSU5ORVIgSU5URVJTRUNUIElTIElTTlVMTCBKT0lOIExBVEVSQUwgTEVBRElORyBMSUtFIExJTUlUIE5BVFVSQUwgTk9UIE5PVE5VTEwgTlVMTCBPRkZTRVQgT04gT05MWSBPUiBPUkRFUiBPVVRFUiBPVkVSTEFQUyBQTEFDSU5HIFBSSU1BUlkgUkVGRVJFTkNFUyBSRVRVUk5JTkcgU0lNSUxBUiBTT01FIFNZTU1FVFJJQyBUQUJMRVNBTVBMRSBUSEVOIFRSQUlMSU5HIFVOSU9OIFVOSVFVRSBVU0lORyBWQVJJQURJQ3wxMCBWRVJCT1NFIFdIRU4gV0hFUkUgV0lORE9XIFdJVEggQlkgUkVUVVJOUyBJTk9VVCBPVVQgU0VUT0Z8MTAgSUYgU1RSSUNUIENVUlJFTlQgQ09OVElOVUUgT1dORVIgTE9DQVRJT04gT1ZFUiBQQVJUSVRJT04gV0lUSElOIEJFVFdFRU4gRVNDQVBFIEVYVEVSTkFMIElOVk9LRVIgREVGSU5FUiBXT1JLIFJFTkFNRSBWRVJTSU9OIENPTk5FQ1RJT04gQ09OTkVDVCBUQUJMRVMgVEVNUCBURU1QT1JBUlkgRlVOQ1RJT05TIFNFUVVFTkNFUyBUWVBFUyBTQ0hFTUFTIE9QVElPTiBDQVNDQURFIFJFU1RSSUNUIEFERCBBRE1JTiBFWElTVFMgVkFMSUQgVkFMSURBVEUgRU5BQkxFIERJU0FCTEUgUkVQTElDQXwxMCBBTFdBWVMgUEFTU0lORyBDT0xVTU5TIFBBVEggUkVGIFZBTFVFIE9WRVJSSURJTkcgSU1NVVRBQkxFIFNUQUJMRSBWT0xBVElMRSBCRUZPUkUgQUZURVIgRUFDSCBST1cgUFJPQ0VEVVJBTCBST1VUSU5FIE5PIEhBTkRMRVIgVkFMSURBVE9SIE9QVElPTlMgU1RPUkFHRSBPSURTfDEwIFdJVEhPVVQgSU5IRVJJVCBERVBFTkRTIENBTExFRCBJTlBVVCBMRUFLUFJPT0Z8MTAgQ09TVCBST1dTIE5PV0FJVCBTRUFSQ0ggVU5USUwgRU5DUllQVEVEfDEwIFBBU1NXT1JEIENPTkZMSUNUfDEwIElOU1RFQUQgSU5IRVJJVFMgQ0hBUkFDVEVSSVNUSUNTIFdSSVRFIENVUlNPUiBBTFNPIFNUQVRFTUVOVCBTSEFSRSBFWENMVVNJVkUgSU5MSU5FIElTT0xBVElPTiBSRVBFQVRBQkxFIFJFQUQgQ09NTUlUVEVEIFNFUklBTElaQUJMRSBVTkNPTU1JVFRFRCBMT0NBTCBHTE9CQUwgU1FMIFBST0NFRFVSRVMgUkVDVVJTSVZFIFNOQVBTSE9UIFJPTExVUCBDVUJFIFRSVVNURUR8MTAgSU5DTFVERSBGT0xMT1dJTkcgUFJFQ0VESU5HIFVOQk9VTkRFRCBSQU5HRSBHUk9VUFMgVU5FTkNSWVBURUR8MTAgU1lTSUQgRk9STUFUIERFTElNSVRFUiBIRUFERVIgUVVPVEUgRU5DT0RJTkcgRklMVEVSIE9GRiBGT1JDRV9RVU9URSBGT1JDRV9OT1RfTlVMTCBGT1JDRV9OVUxMIENPU1RTIEJVRkZFUlMgVElNSU5HIFNVTU1BUlkgRElTQUJMRV9QQUdFX1NLSVBQSU5HIFJFU1RBUlQgQ1lDTEUgR0VORVJBVEVEIElERU5USVRZIERFRkVSUkVEIElNTUVESUFURSBMRVZFTCBMT0dHRUQgVU5MT0dHRUQgT0YgTk9USElORyBOT05FIEVYQ0xVREUgQVRUUklCVVRFIFVTQUdFIFJPVVRJTkVTIFRSVUUgRkFMU0UgTkFOIElORklOSVRZIEFMSUFTIEJFR0lOIENPTlNUQU5UIERFQ0xBUkUgRU5EIEVYQ0VQVElPTiBSRVRVUk4gUEVSRk9STXwxMCBSQUlTRSBHRVQgRElBR05PU1RJQ1MgU1RBQ0tFRHwxMCBGT1JFQUNIIExPT1AgRUxTSUYgRVhJVCBXSElMRSBSRVZFUlNFIFNMSUNFIERFQlVHIExPRyBJTkZPIE5PVElDRSBXQVJOSU5HIEFTU0VSVCBPUEVOIFNVUEVSVVNFUiBOT1NVUEVSVVNFUiBDUkVBVEVEQiBOT0NSRUFURURCIENSRUFURVJPTEUgTk9DUkVBVEVST0xFIElOSEVSSVQgTk9JTkhFUklUIExPR0lOIE5PTE9HSU4gUkVQTElDQVRJT04gTk9SRVBMSUNBVElPTiBCWVBBU1NSTFMgTk9CWVBBU1NSTFMgIixidWlsdF9pbjoiQ1VSUkVOVF9USU1FIENVUlJFTlRfVElNRVNUQU1QIENVUlJFTlRfVVNFUiBDVVJSRU5UX0NBVEFMT0d8MTAgQ1VSUkVOVF9EQVRFIExPQ0FMVElNRSBMT0NBTFRJTUVTVEFNUCBDVVJSRU5UX1JPTEV8MTAgQ1VSUkVOVF9TQ0hFTUF8MTAgU0VTU0lPTl9VU0VSIFBVQkxJQyBGT1VORCBORVcgT0xEIFRHX05BTUV8MTAgVEdfV0hFTnwxMCBUR19MRVZFTHwxMCBUR19PUHwxMCBUR19SRUxJRHwxMCBUR19SRUxOQU1FfDEwIFRHX1RBQkxFX05BTUV8MTAgVEdfVEFCTEVfU0NIRU1BfDEwIFRHX05BUkdTfDEwIFRHX0FSR1Z8MTAgVEdfRVZFTlR8MTAgVEdfVEFHfDEwIFJPV19DT1VOVCBSRVNVTFRfT0lEfDEwIFBHX0NPTlRFWFR8MTAgUkVUVVJORURfU1FMU1RBVEUgQ09MVU1OX05BTUUgQ09OU1RSQUlOVF9OQU1FIFBHX0RBVEFUWVBFX05BTUV8MTAgTUVTU0FHRV9URVhUIFRBQkxFX05BTUUgU0NIRU1BX05BTUUgUEdfRVhDRVBUSU9OX0RFVEFJTHwxMCBQR19FWENFUFRJT05fSElOVHwxMCBQR19FWENFUFRJT05fQ09OVEVYVHwxMCBTUUxTVEFURSBTUUxFUlJNfDEwIFNVQ0NFU1NGVUxfQ09NUExFVElPTiBXQVJOSU5HIERZTkFNSUNfUkVTVUxUX1NFVFNfUkVUVVJORUQgSU1QTElDSVRfWkVST19CSVRfUEFERElORyBOVUxMX1ZBTFVFX0VMSU1JTkFURURfSU5fU0VUX0ZVTkNUSU9OIFBSSVZJTEVHRV9OT1RfR1JBTlRFRCBQUklWSUxFR0VfTk9UX1JFVk9LRUQgU1RSSU5HX0RBVEFfUklHSFRfVFJVTkNBVElPTiBERVBSRUNBVEVEX0ZFQVRVUkUgTk9fREFUQSBOT19BRERJVElPTkFMX0RZTkFNSUNfUkVTVUxUX1NFVFNfUkVUVVJORUQgU1FMX1NUQVRFTUVOVF9OT1RfWUVUX0NPTVBMRVRFIENPTk5FQ1RJT05fRVhDRVBUSU9OIENPTk5FQ1RJT05fRE9FU19OT1RfRVhJU1QgQ09OTkVDVElPTl9GQUlMVVJFIFNRTENMSUVOVF9VTkFCTEVfVE9fRVNUQUJMSVNIX1NRTENPTk5FQ1RJT04gU1FMU0VSVkVSX1JFSkVDVEVEX0VTVEFCTElTSE1FTlRfT0ZfU1FMQ09OTkVDVElPTiBUUkFOU0FDVElPTl9SRVNPTFVUSU9OX1VOS05PV04gUFJPVE9DT0xfVklPTEFUSU9OIFRSSUdHRVJFRF9BQ1RJT05fRVhDRVBUSU9OIEZFQVRVUkVfTk9UX1NVUFBPUlRFRCBJTlZBTElEX1RSQU5TQUNUSU9OX0lOSVRJQVRJT04gTE9DQVRPUl9FWENFUFRJT04gSU5WQUxJRF9MT0NBVE9SX1NQRUNJRklDQVRJT04gSU5WQUxJRF9HUkFOVE9SIElOVkFMSURfR1JBTlRfT1BFUkFUSU9OIElOVkFMSURfUk9MRV9TUEVDSUZJQ0FUSU9OIERJQUdOT1NUSUNTX0VYQ0VQVElPTiBTVEFDS0VEX0RJQUdOT1NUSUNTX0FDQ0VTU0VEX1dJVEhPVVRfQUNUSVZFX0hBTkRMRVIgQ0FTRV9OT1RfRk9VTkQgQ0FSRElOQUxJVFlfVklPTEFUSU9OIERBVEFfRVhDRVBUSU9OIEFSUkFZX1NVQlNDUklQVF9FUlJPUiBDSEFSQUNURVJfTk9UX0lOX1JFUEVSVE9JUkUgREFURVRJTUVfRklFTERfT1ZFUkZMT1cgRElWSVNJT05fQllfWkVSTyBFUlJPUl9JTl9BU1NJR05NRU5UIEVTQ0FQRV9DSEFSQUNURVJfQ09ORkxJQ1QgSU5ESUNBVE9SX09WRVJGTE9XIElOVEVSVkFMX0ZJRUxEX09WRVJGTE9XIElOVkFMSURfQVJHVU1FTlRfRk9SX0xPR0FSSVRITSBJTlZBTElEX0FSR1VNRU5UX0ZPUl9OVElMRV9GVU5DVElPTiBJTlZBTElEX0FSR1VNRU5UX0ZPUl9OVEhfVkFMVUVfRlVOQ1RJT04gSU5WQUxJRF9BUkdVTUVOVF9GT1JfUE9XRVJfRlVOQ1RJT04gSU5WQUxJRF9BUkdVTUVOVF9GT1JfV0lEVEhfQlVDS0VUX0ZVTkNUSU9OIElOVkFMSURfQ0hBUkFDVEVSX1ZBTFVFX0ZPUl9DQVNUIElOVkFMSURfREFURVRJTUVfRk9STUFUIElOVkFMSURfRVNDQVBFX0NIQVJBQ1RFUiBJTlZBTElEX0VTQ0FQRV9PQ1RFVCBJTlZBTElEX0VTQ0FQRV9TRVFVRU5DRSBOT05TVEFOREFSRF9VU0VfT0ZfRVNDQVBFX0NIQVJBQ1RFUiBJTlZBTElEX0lORElDQVRPUl9QQVJBTUVURVJfVkFMVUUgSU5WQUxJRF9QQVJBTUVURVJfVkFMVUUgSU5WQUxJRF9SRUdVTEFSX0VYUFJFU1NJT04gSU5WQUxJRF9ST1dfQ09VTlRfSU5fTElNSVRfQ0xBVVNFIElOVkFMSURfUk9XX0NPVU5UX0lOX1JFU1VMVF9PRkZTRVRfQ0xBVVNFIElOVkFMSURfVEFCTEVTQU1QTEVfQVJHVU1FTlQgSU5WQUxJRF9UQUJMRVNBTVBMRV9SRVBFQVQgSU5WQUxJRF9USU1FX1pPTkVfRElTUExBQ0VNRU5UX1ZBTFVFIElOVkFMSURfVVNFX09GX0VTQ0FQRV9DSEFSQUNURVIgTU9TVF9TUEVDSUZJQ19UWVBFX01JU01BVENIIE5VTExfVkFMVUVfTk9UX0FMTE9XRUQgTlVMTF9WQUxVRV9OT19JTkRJQ0FUT1JfUEFSQU1FVEVSIE5VTUVSSUNfVkFMVUVfT1VUX09GX1JBTkdFIFNFUVVFTkNFX0dFTkVSQVRPUl9MSU1JVF9FWENFRURFRCBTVFJJTkdfREFUQV9MRU5HVEhfTUlTTUFUQ0ggU1RSSU5HX0RBVEFfUklHSFRfVFJVTkNBVElPTiBTVUJTVFJJTkdfRVJST1IgVFJJTV9FUlJPUiBVTlRFUk1JTkFURURfQ19TVFJJTkcgWkVST19MRU5HVEhfQ0hBUkFDVEVSX1NUUklORyBGTE9BVElOR19QT0lOVF9FWENFUFRJT04gSU5WQUxJRF9URVhUX1JFUFJFU0VOVEFUSU9OIElOVkFMSURfQklOQVJZX1JFUFJFU0VOVEFUSU9OIEJBRF9DT1BZX0ZJTEVfRk9STUFUIFVOVFJBTlNMQVRBQkxFX0NIQVJBQ1RFUiBOT1RfQU5fWE1MX0RPQ1VNRU5UIElOVkFMSURfWE1MX0RPQ1VNRU5UIElOVkFMSURfWE1MX0NPTlRFTlQgSU5WQUxJRF9YTUxfQ09NTUVOVCBJTlZBTElEX1hNTF9QUk9DRVNTSU5HX0lOU1RSVUNUSU9OIElOVEVHUklUWV9DT05TVFJBSU5UX1ZJT0xBVElPTiBSRVNUUklDVF9WSU9MQVRJT04gTk9UX05VTExfVklPTEFUSU9OIEZPUkVJR05fS0VZX1ZJT0xBVElPTiBVTklRVUVfVklPTEFUSU9OIENIRUNLX1ZJT0xBVElPTiBFWENMVVNJT05fVklPTEFUSU9OIElOVkFMSURfQ1VSU09SX1NUQVRFIElOVkFMSURfVFJBTlNBQ1RJT05fU1RBVEUgQUNUSVZFX1NRTF9UUkFOU0FDVElPTiBCUkFOQ0hfVFJBTlNBQ1RJT05fQUxSRUFEWV9BQ1RJVkUgSEVMRF9DVVJTT1JfUkVRVUlSRVNfU0FNRV9JU09MQVRJT05fTEVWRUwgSU5BUFBST1BSSUFURV9BQ0NFU1NfTU9ERV9GT1JfQlJBTkNIX1RSQU5TQUNUSU9OIElOQVBQUk9QUklBVEVfSVNPTEFUSU9OX0xFVkVMX0ZPUl9CUkFOQ0hfVFJBTlNBQ1RJT04gTk9fQUNUSVZFX1NRTF9UUkFOU0FDVElPTl9GT1JfQlJBTkNIX1RSQU5TQUNUSU9OIFJFQURfT05MWV9TUUxfVFJBTlNBQ1RJT04gU0NIRU1BX0FORF9EQVRBX1NUQVRFTUVOVF9NSVhJTkdfTk9UX1NVUFBPUlRFRCBOT19BQ1RJVkVfU1FMX1RSQU5TQUNUSU9OIElOX0ZBSUxFRF9TUUxfVFJBTlNBQ1RJT04gSURMRV9JTl9UUkFOU0FDVElPTl9TRVNTSU9OX1RJTUVPVVQgSU5WQUxJRF9TUUxfU1RBVEVNRU5UX05BTUUgVFJJR0dFUkVEX0RBVEFfQ0hBTkdFX1ZJT0xBVElPTiBJTlZBTElEX0FVVEhPUklaQVRJT05fU1BFQ0lGSUNBVElPTiBJTlZBTElEX1BBU1NXT1JEIERFUEVOREVOVF9QUklWSUxFR0VfREVTQ1JJUFRPUlNfU1RJTExfRVhJU1QgREVQRU5ERU5UX09CSkVDVFNfU1RJTExfRVhJU1QgSU5WQUxJRF9UUkFOU0FDVElPTl9URVJNSU5BVElPTiBTUUxfUk9VVElORV9FWENFUFRJT04gRlVOQ1RJT05fRVhFQ1VURURfTk9fUkVUVVJOX1NUQVRFTUVOVCBNT0RJRllJTkdfU1FMX0RBVEFfTk9UX1BFUk1JVFRFRCBQUk9ISUJJVEVEX1NRTF9TVEFURU1FTlRfQVRURU1QVEVEIFJFQURJTkdfU1FMX0RBVEFfTk9UX1BFUk1JVFRFRCBJTlZBTElEX0NVUlNPUl9OQU1FIEVYVEVSTkFMX1JPVVRJTkVfRVhDRVBUSU9OIENPTlRBSU5JTkdfU1FMX05PVF9QRVJNSVRURUQgTU9ESUZZSU5HX1NRTF9EQVRBX05PVF9QRVJNSVRURUQgUFJPSElCSVRFRF9TUUxfU1RBVEVNRU5UX0FUVEVNUFRFRCBSRUFESU5HX1NRTF9EQVRBX05PVF9QRVJNSVRURUQgRVhURVJOQUxfUk9VVElORV9JTlZPQ0FUSU9OX0VYQ0VQVElPTiBJTlZBTElEX1NRTFNUQVRFX1JFVFVSTkVEIE5VTExfVkFMVUVfTk9UX0FMTE9XRUQgVFJJR0dFUl9QUk9UT0NPTF9WSU9MQVRFRCBTUkZfUFJPVE9DT0xfVklPTEFURUQgRVZFTlRfVFJJR0dFUl9QUk9UT0NPTF9WSU9MQVRFRCBTQVZFUE9JTlRfRVhDRVBUSU9OIElOVkFMSURfU0FWRVBPSU5UX1NQRUNJRklDQVRJT04gSU5WQUxJRF9DQVRBTE9HX05BTUUgSU5WQUxJRF9TQ0hFTUFfTkFNRSBUUkFOU0FDVElPTl9ST0xMQkFDSyBUUkFOU0FDVElPTl9JTlRFR1JJVFlfQ09OU1RSQUlOVF9WSU9MQVRJT04gU0VSSUFMSVpBVElPTl9GQUlMVVJFIFNUQVRFTUVOVF9DT01QTEVUSU9OX1VOS05PV04gREVBRExPQ0tfREVURUNURUQgU1lOVEFYX0VSUk9SX09SX0FDQ0VTU19SVUxFX1ZJT0xBVElPTiBTWU5UQVhfRVJST1IgSU5TVUZGSUNJRU5UX1BSSVZJTEVHRSBDQU5OT1RfQ09FUkNFIEdST1VQSU5HX0VSUk9SIFdJTkRPV0lOR19FUlJPUiBJTlZBTElEX1JFQ1VSU0lPTiBJTlZBTElEX0ZPUkVJR05fS0VZIElOVkFMSURfTkFNRSBOQU1FX1RPT19MT05HIFJFU0VSVkVEX05BTUUgREFUQVRZUEVfTUlTTUFUQ0ggSU5ERVRFUk1JTkFURV9EQVRBVFlQRSBDT0xMQVRJT05fTUlTTUFUQ0ggSU5ERVRFUk1JTkFURV9DT0xMQVRJT04gV1JPTkdfT0JKRUNUX1RZUEUgR0VORVJBVEVEX0FMV0FZUyBVTkRFRklORURfQ09MVU1OIFVOREVGSU5FRF9GVU5DVElPTiBVTkRFRklORURfVEFCTEUgVU5ERUZJTkVEX1BBUkFNRVRFUiBVTkRFRklORURfT0JKRUNUIERVUExJQ0FURV9DT0xVTU4gRFVQTElDQVRFX0NVUlNPUiBEVVBMSUNBVEVfREFUQUJBU0UgRFVQTElDQVRFX0ZVTkNUSU9OIERVUExJQ0FURV9QUkVQQVJFRF9TVEFURU1FTlQgRFVQTElDQVRFX1NDSEVNQSBEVVBMSUNBVEVfVEFCTEUgRFVQTElDQVRFX0FMSUFTIERVUExJQ0FURV9PQkpFQ1QgQU1CSUdVT1VTX0NPTFVNTiBBTUJJR1VPVVNfRlVOQ1RJT04gQU1CSUdVT1VTX1BBUkFNRVRFUiBBTUJJR1VPVVNfQUxJQVMgSU5WQUxJRF9DT0xVTU5fUkVGRVJFTkNFIElOVkFMSURfQ09MVU1OX0RFRklOSVRJT04gSU5WQUxJRF9DVVJTT1JfREVGSU5JVElPTiBJTlZBTElEX0RBVEFCQVNFX0RFRklOSVRJT04gSU5WQUxJRF9GVU5DVElPTl9ERUZJTklUSU9OIElOVkFMSURfUFJFUEFSRURfU1RBVEVNRU5UX0RFRklOSVRJT04gSU5WQUxJRF9TQ0hFTUFfREVGSU5JVElPTiBJTlZBTElEX1RBQkxFX0RFRklOSVRJT04gSU5WQUxJRF9PQkpFQ1RfREVGSU5JVElPTiBXSVRIX0NIRUNLX09QVElPTl9WSU9MQVRJT04gSU5TVUZGSUNJRU5UX1JFU09VUkNFUyBESVNLX0ZVTEwgT1VUX09GX01FTU9SWSBUT09fTUFOWV9DT05ORUNUSU9OUyBDT05GSUdVUkFUSU9OX0xJTUlUX0VYQ0VFREVEIFBST0dSQU1fTElNSVRfRVhDRUVERUQgU1RBVEVNRU5UX1RPT19DT01QTEVYIFRPT19NQU5ZX0NPTFVNTlMgVE9PX01BTllfQVJHVU1FTlRTIE9CSkVDVF9OT1RfSU5fUFJFUkVRVUlTSVRFX1NUQVRFIE9CSkVDVF9JTl9VU0UgQ0FOVF9DSEFOR0VfUlVOVElNRV9QQVJBTSBMT0NLX05PVF9BVkFJTEFCTEUgT1BFUkFUT1JfSU5URVJWRU5USU9OIFFVRVJZX0NBTkNFTEVEIEFETUlOX1NIVVRET1dOIENSQVNIX1NIVVRET1dOIENBTk5PVF9DT05ORUNUX05PVyBEQVRBQkFTRV9EUk9QUEVEIFNZU1RFTV9FUlJPUiBJT19FUlJPUiBVTkRFRklORURfRklMRSBEVVBMSUNBVEVfRklMRSBTTkFQU0hPVF9UT09fT0xEIENPTkZJR19GSUxFX0VSUk9SIExPQ0tfRklMRV9FWElTVFMgRkRXX0VSUk9SIEZEV19DT0xVTU5fTkFNRV9OT1RfRk9VTkQgRkRXX0RZTkFNSUNfUEFSQU1FVEVSX1ZBTFVFX05FRURFRCBGRFdfRlVOQ1RJT05fU0VRVUVOQ0VfRVJST1IgRkRXX0lOQ09OU0lTVEVOVF9ERVNDUklQVE9SX0lORk9STUFUSU9OIEZEV19JTlZBTElEX0FUVFJJQlVURV9WQUxVRSBGRFdfSU5WQUxJRF9DT0xVTU5fTkFNRSBGRFdfSU5WQUxJRF9DT0xVTU5fTlVNQkVSIEZEV19JTlZBTElEX0RBVEFfVFlQRSBGRFdfSU5WQUxJRF9EQVRBX1RZUEVfREVTQ1JJUFRPUlMgRkRXX0lOVkFMSURfREVTQ1JJUFRPUl9GSUVMRF9JREVOVElGSUVSIEZEV19JTlZBTElEX0hBTkRMRSBGRFdfSU5WQUxJRF9PUFRJT05fSU5ERVggRkRXX0lOVkFMSURfT1BUSU9OX05BTUUgRkRXX0lOVkFMSURfU1RSSU5HX0xFTkdUSF9PUl9CVUZGRVJfTEVOR1RIIEZEV19JTlZBTElEX1NUUklOR19GT1JNQVQgRkRXX0lOVkFMSURfVVNFX09GX05VTExfUE9JTlRFUiBGRFdfVE9PX01BTllfSEFORExFUyBGRFdfT1VUX09GX01FTU9SWSBGRFdfTk9fU0NIRU1BUyBGRFdfT1BUSU9OX05BTUVfTk9UX0ZPVU5EIEZEV19SRVBMWV9IQU5ETEUgRkRXX1NDSEVNQV9OT1RfRk9VTkQgRkRXX1RBQkxFX05PVF9GT1VORCBGRFdfVU5BQkxFX1RPX0NSRUFURV9FWEVDVVRJT04gRkRXX1VOQUJMRV9UT19DUkVBVEVfUkVQTFkgRkRXX1VOQUJMRV9UT19FU1RBQkxJU0hfQ09OTkVDVElPTiBQTFBHU1FMX0VSUk9SIFJBSVNFX0VYQ0VQVElPTiBOT19EQVRBX0ZPVU5EIFRPT19NQU5ZX1JPV1MgQVNTRVJUX0ZBSUxVUkUgSU5URVJOQUxfRVJST1IgREFUQV9DT1JSVVBURUQgSU5ERVhfQ09SUlVQVEVEICJ9LGk6Lzo9PXxcV1xzKlwoXCp8KF58XHMpXCRbYS16XXx7e3xbYS16XTpccyokfFwuXC5cLnxUTzp8RE86LyxjOlt7Y046ImtleXdvcmQiLHY6W3tiOi9cYlRFWFRccypTRUFSQ0hcYi99LHtiOi9cYihQUklNQVJZfEZPUkVJR058Rk9SKFxzK05PKT8pXHMrS0VZXGIvfSx7YjovXGJQQVJBTExFTFxzKyhVTlNBRkV8UkVTVFJJQ1RFRHxTQUZFKVxiL30se2I6L1xiU1RPUkFHRVxzKyhQTEFJTnxFWFRFUk5BTHxFWFRFTkRFRHxNQUlOKVxiL30se2I6L1xiTUFUQ0hccysoRlVMTHxQQVJUSUFMfFNJTVBMRSlcYi99LHtiOi9cYk5VTExTXHMrKEZJUlNUfExBU1QpXGIvfSx7YjovXGJFVkVOVFxzK1RSSUdHRVJcYi99LHtiOi9cYihNQVBQSU5HfE9SKVxzK1JFUExBQ0VcYi99LHtiOi9cYihGUk9NfFRPKVxzKyhQUk9HUkFNfFNURElOfFNURE9VVClcYi99LHtiOi9cYihTSEFSRXxFWENMVVNJVkUpXHMrTU9ERVxiL30se2I6L1xiKExFRlR8UklHSFQpXHMrKE9VVEVSXHMrKT9KT0lOXGIvfSx7YjovXGIoRkVUQ0h8TU9WRSlccysoTkVYVHxQUklPUnxGSVJTVHxMQVNUfEFCU09MVVRFfFJFTEFUSVZFfEZPUldBUkR8QkFDS1dBUkQpXGIvfSx7YjovXGJQUkVTRVJWRVxzK1JPV1NcYi99LHtiOi9cYkRJU0NBUkRccytQTEFOU1xiL30se2I6L1xiUkVGRVJFTkNJTkdccysoT0xEfE5FVylcYi99LHtiOi9cYlNLSVBccytMT0NLRURcYi99LHtiOi9cYkdST1VQSU5HXHMrU0VUU1xiL30se2I6L1xiKEJJTkFSWXxJTlNFTlNJVElWRXxTQ1JPTEx8Tk9ccytTQ1JPTEwpXHMrKENVUlNPUnxGT1IpXGIvfSx7YjovXGIoV0lUSHxXSVRIT1VUKVxzK0hPTERcYi99LHtiOi9cYldJVEhccysoQ0FTQ0FERUR8TE9DQUwpXHMrQ0hFQ0tccytPUFRJT05cYi99LHtiOi9cYkVYQ0xVREVccysoVElFU3xOT1xzK09USEVSUylcYi99LHtiOi9cYkZPUk1BVFxzKyhURVhUfFhNTHxKU09OfFlBTUwpXGIvfSx7YjovXGJTRVRccysoKFNFU1NJT058TE9DQUwpXHMrKT9OQU1FU1xiL30se2I6L1xiSVNccysoTk9UXHMrKT9VTktOT1dOXGIvfSx7YjovXGJTRUNVUklUWVxzK0xBQkVMXGIvfSx7YjovXGJTVEFOREFMT05FXHMrKFlFU3xOT3xOT1xzK1ZBTFVFKVxiL30se2I6L1xiV0lUSFxzKyhOT1xzKyk/REFUQVxiL30se2I6L1xiKEZPUkVJR058U0VUKVxzK0RBVEFcYi99LHtiOi9cYlNFVFxzKyhDQVRBTE9HfENPTlNUUkFJTlRTKVxiL30se2I6L1xiKFdJVEh8Rk9SKVxzK09SRElOQUxJVFlcYi99LHtiOi9cYklTXHMrKE5PVFxzKyk/RE9DVU1FTlRcYi99LHtiOi9cYlhNTFxzK09QVElPTlxzKyhET0NVTUVOVHxDT05URU5UKVxiL30se2I6L1xiKFNUUklQfFBSRVNFUlZFKVxzK1dISVRFU1BBQ0VcYi99LHtiOi9cYk5PXHMrKEFDVElPTnxNQVhWQUxVRXxNSU5WQUxVRSlcYi99LHtiOi9cYlBBUlRJVElPTlxzK0JZXHMrKFJBTkdFfExJU1R8SEFTSClcYi99LHtiOi9cYkFUXHMrVElNRVxzK1pPTkVcYi99LHtiOi9cYkdSQU5URURccytCWVxiL30se2I6L1xiUkVUVVJOXHMrKFFVRVJZfE5FWFQpXGIvfSx7YjovXGIoQVRUQUNIfERFVEFDSClccytQQVJUSVRJT05cYi99LHtiOi9cYkZPUkNFXHMrUk9XXHMrTEVWRUxccytTRUNVUklUWVxiL30se2I6L1xiKElOQ0xVRElOR3xFWENMVURJTkcpXHMrKENPTU1FTlRTfENPTlNUUkFJTlRTfERFRkFVTFRTfElERU5USVRZfElOREVYRVN8U1RBVElTVElDU3xTVE9SQUdFfEFMTClcYi99LHtiOi9cYkFTXHMrKEFTU0lHTk1FTlR8SU1QTElDSVR8UEVSTUlTU0lWRXxSRVNUUklDVElWRXxFTlVNfFJBTkdFKVxiL31dfSx7YjovXGIoRk9STUFUfEZBTUlMWXxWRVJTSU9OKVxzKlwoL30se2I6L1xiSU5DTFVERVxzKlwoLyxrOiJJTkNMVURFIn0se2I6L1xiUkFOR0UoPyFccyooQkVUV0VFTnxVTkJPVU5ERUR8Q1VSUkVOVHxbLTAtOV0rKSkvfSx7YjovXGIoVkVSU0lPTnxPV05FUnxURU1QTEFURXxUQUJMRVNQQUNFfENPTk5FQ1RJT05ccytMSU1JVHxQUk9DRURVUkV8UkVTVFJJQ1R8Sk9JTnxQQVJTRVJ8Q09QWXxTVEFSVHxFTkR8Q09MTEFUSU9OfElOUFVUfEFOQUxZWkV8U1RPUkFHRXxMSUtFfERFRkFVTFR8REVMSU1JVEVSfEVOQ09ESU5HfENPTFVNTnxDT05TVFJBSU5UfFRBQkxFfFNDSEVNQSlccyo9L30se2I6L1xiKFBHX1x3Kz98SEFTX1tBLVpfXStfUFJJVklMRUdFKVxiLyxyOjEwfSx7YjovXGJFWFRSQUNUXHMqXCgvLGU6L1xiRlJPTVxiLyxyRTohMCxrOnt0eXBlOiJDRU5UVVJZIERBWSBERUNBREUgRE9XIERPWSBFUE9DSCBIT1VSIElTT0RPVyBJU09ZRUFSIE1JQ1JPU0VDT05EUyBNSUxMRU5OSVVNIE1JTExJU0VDT05EUyBNSU5VVEUgTU9OVEggUVVBUlRFUiBTRUNPTkQgVElNRVpPTkUgVElNRVpPTkVfSE9VUiBUSU1FWk9ORV9NSU5VVEUgV0VFSyBZRUFSIn19LHtiOi9cYihYTUxFTEVNRU5UfFhNTFBJKVxzKlwoXHMqTkFNRS8sazp7a2V5d29yZDoiTkFNRSJ9fSx7YjovXGIoWE1MUEFSU0V8WE1MU0VSSUFMSVpFKVxzKlwoXHMqKERPQ1VNRU5UfENPTlRFTlQpLyxrOntrZXl3b3JkOiJET0NVTUVOVCBDT05URU5UIn19LHtiSzoiQ0FDSEUgSU5DUkVNRU5UIE1BWFZBTFVFIE1JTlZBTFVFIixlOmUuQ05SLHJFOiEwLGs6IkJZIENBQ0hFIElOQ1JFTUVOVCBNQVhWQUxVRSBNSU5WQUxVRSJ9LHtjTjoidHlwZSIsYjovXGIoV0lUSHxXSVRIT1VUKVxzK1RJTUVccytaT05FXGIvfSx7Y046InR5cGUiLGI6L1xiSU5URVJWQUxccysoWUVBUnxNT05USHxEQVl8SE9VUnxNSU5VVEV8U0VDT05EKShccytUT1xzKyhNT05USHxIT1VSfE1JTlVURXxTRUNPTkQpKT9cYi99LHtiOi9cYlJFVFVSTlNccysoTEFOR1VBR0VfSEFORExFUnxUUklHR0VSfEVWRU5UX1RSSUdHRVJ8RkRXX0hBTkRMRVJ8SU5ERVhfQU1fSEFORExFUnxUU01fSEFORExFUilcYi8sazp7a2V5d29yZDoiUkVUVVJOUyIsdHlwZToiTEFOR1VBR0VfSEFORExFUiBUUklHR0VSIEVWRU5UX1RSSUdHRVIgRkRXX0hBTkRMRVIgSU5ERVhfQU1fSEFORExFUiBUU01fSEFORExFUiJ9fSx7YjoiXFxiKCIrbysiKVxccypcXCgifSx7YjoiXFwuKCIrYSsiKVxcYiJ9LHtiOiJcXGIoIithKyIpXFxzK1BBVEhcXGIiLGs6e2tleXdvcmQ6IlBBVEgiLHR5cGU6ci5yZXBsYWNlKCJQQVRIICIsIiIpfX0se2NOOiJ0eXBlIixiOiJcXGIoIithKyIpXFxiIn0se2NOOiJzdHJpbmciLGI6IiciLGU6IiciLGM6W3tiOiInJyJ9XX0se2NOOiJzdHJpbmciLGI6IihlfEV8dSZ8VSYpJyIsZToiJyIsYzpbe2I6IlxcXFwuIn1dLHI6MTB9LHtiOiJcXCQoW2EtekEtWl9dP3xbYS16QS1aX11bYS16QS1aXzAtOV0qKVxcJCIsZW5kU2FtZUFzQmVnaW46ITAsYzpbe3NMOlsicGdzcWwiLCJwZXJsIiwicHl0aG9uIiwidGNsIiwiciIsImx1YSIsImphdmEiLCJwaHAiLCJydWJ5IiwiYmFzaCIsInNjaGVtZSIsInhtbCIsImpzb24iXSxlVzohMH1dfSx7YjonIicsZTonIicsYzpbe2I6JyIiJ31dfSxlLkNOTSxlLkNCQ00sdCx7Y046Im1ldGEiLHY6W3tiOiIlKFJPVyk/VFlQRSIscjoxMH0se2I6IlxcJFxcZCsifSx7YjoiXiNcXHciLGU6IiQifV19LHtjTjoic3ltYm9sIixiOiI8PFxccypbYS16QS1aX11bYS16QS1aXzAtOSRdKlxccyo+PiIscjoxMH1dfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgicGhwIixmdW5jdGlvbihlKXt2YXIgdD17YjoiXFwkK1thLXpBLVpffy3Dv11bYS16QS1aMC05X38tw79dKiJ9LHI9e2NOOiJtZXRhIixiOi88XD8ocGhwKT98XD8+L30sYT17Y046InN0cmluZyIsYzpbZS5CRSxyXSx2Olt7YjonYiInLGU6JyInfSx7YjoiYiciLGU6IicifSxlLmluaGVyaXQoZS5BU00se2k6bnVsbH0pLGUuaW5oZXJpdChlLlFTTSx7aTpudWxsfSldfSxvPXt2OltlLkJOTSxlLkNOTV19O3JldHVybnthbGlhc2VzOlsicGhwIiwicGhwMyIsInBocDQiLCJwaHA1IiwicGhwNiIsInBocDciXSxjSTohMCxrOiJhbmQgaW5jbHVkZV9vbmNlIGxpc3QgYWJzdHJhY3QgZ2xvYmFsIHByaXZhdGUgZWNobyBpbnRlcmZhY2UgYXMgc3RhdGljIGVuZHN3aXRjaCBhcnJheSBudWxsIGlmIGVuZHdoaWxlIG9yIGNvbnN0IGZvciBlbmRmb3JlYWNoIHNlbGYgdmFyIHdoaWxlIGlzc2V0IHB1YmxpYyBwcm90ZWN0ZWQgZXhpdCBmb3JlYWNoIHRocm93IGVsc2VpZiBpbmNsdWRlIF9fRklMRV9fIGVtcHR5IHJlcXVpcmVfb25jZSBkbyB4b3IgcmV0dXJuIHBhcmVudCBjbG9uZSB1c2UgX19DTEFTU19fIF9fTElORV9fIGVsc2UgYnJlYWsgcHJpbnQgZXZhbCBuZXcgY2F0Y2ggX19NRVRIT0RfXyBjYXNlIGV4Y2VwdGlvbiBkZWZhdWx0IGRpZSByZXF1aXJlIF9fRlVOQ1RJT05fXyBlbmRkZWNsYXJlIGZpbmFsIHRyeSBzd2l0Y2ggY29udGludWUgZW5kZm9yIGVuZGlmIGRlY2xhcmUgdW5zZXQgdHJ1ZSBmYWxzZSB0cmFpdCBnb3RvIGluc3RhbmNlb2YgaW5zdGVhZG9mIF9fRElSX18gX19OQU1FU1BBQ0VfXyB5aWVsZCBmaW5hbGx5IixjOltlLkhDTSxlLkMoIi8vIiwiJCIse2M6W3JdfSksZS5DKCIvXFwqIiwiXFwqLyIse2M6W3tjTjoiZG9jdGFnIixiOiJAW0EtWmEtel0rIn1dfSksZS5DKCJfX2hhbHRfY29tcGlsZXIuKz87IiwhMSx7ZVc6ITAsazoiX19oYWx0X2NvbXBpbGVyIixsOmUuVUlSfSkse2NOOiJzdHJpbmciLGI6Lzw8PFsnIl0/XHcrWyciXT8kLyxlOi9eXHcrOz8kLyxjOltlLkJFLHtjTjoic3Vic3QiLHY6W3tiOi9cJFx3Ky99LHtiOi9ce1wkLyxlOi9cfS99XX1dfSxyLHtjTjoia2V5d29yZCIsYjovXCR0aGlzXGIvfSx0LHtiOi8oOjp8LT4pK1thLXpBLVpfXHg3Zi1ceGZmXVthLXpBLVowLTlfXHg3Zi1ceGZmXSovfSx7Y046ImZ1bmN0aW9uIixiSzoiZnVuY3Rpb24iLGU6L1s7e10vLGVFOiEwLGk6IlxcJHxcXFt8JSIsYzpbZS5VVE0se2NOOiJwYXJhbXMiLGI6IlxcKCIsZToiXFwpIixjOlsic2VsZiIsdCxlLkNCQ00sYSxvXX1dfSx7Y046ImNsYXNzIixiSzoiY2xhc3MgaW50ZXJmYWNlIixlOiJ7IixlRTohMCxpOi9bOlwoXCQiXS8sYzpbe2JLOiJleHRlbmRzIGltcGxlbWVudHMifSxlLlVUTV19LHtiSzoibmFtZXNwYWNlIixlOiI7IixpOi9bXC4nXS8sYzpbZS5VVE1dfSx7Yks6InVzZSIsZToiOyIsYzpbZS5VVE1dfSx7YjoiPT4ifSxhLG9dfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgicGxhaW50ZXh0IixmdW5jdGlvbihlKXtyZXR1cm57YWxpYXNlczpbInRleHQiLCJ0eHQiLCJwbGFpbiIsInBsYWludGV4dCJdLGRpc2FibGVBdXRvZGV0ZWN0OiEwfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgicG93ZXJzaGVsbCIsZnVuY3Rpb24oZSl7dmFyIHQ9e2I6ImBbXFxzXFxTXSIscjowfSxyPXtjTjoidmFyaWFibGUiLHY6W3tiOi9cJFtcd1xkXVtcd1xkXzpdKi99XX0sYT17Y046InN0cmluZyIsdjpbe2I6LyIvLGU6LyIvfSx7YjovQCIvLGU6L14iQC99XSxjOlt0LHIse2NOOiJ2YXJpYWJsZSIsYjovXCRbQS16XS8sZTovW15BLXpdL31dfSxvPWUuaW5oZXJpdChlLkMobnVsbCxudWxsKSx7djpbe2I6LyMvLGU6LyQvfSx7YjovPCMvLGU6LyM+L31dLGM6W3tjTjoiZG9jdGFnIix2Olt7YjovXC4oc3lub3BzaXN8ZGVzY3JpcHRpb258ZXhhbXBsZXxpbnB1dHN8b3V0cHV0c3xub3Rlc3xsaW5rfGNvbXBvbmVudHxyb2xlfGZ1bmN0aW9uYWxpdHkpL30se2I6L1wuKHBhcmFtZXRlcnxmb3J3YXJkaGVscHRhcmdldG5hbWV8Zm9yd2FyZGhlbHBjYXRlZ29yeXxyZW1vdGVoZWxwcnVuc3BhY2V8ZXh0ZXJuYWxoZWxwKVxzK1xTKy99XX1dfSk7cmV0dXJue2FsaWFzZXM6WyJwcyJdLGw6Ly0/W0EtelwuXC1dKy8sY0k6ITAsazp7a2V5d29yZDoiaWYgZWxzZSBmb3JlYWNoIHJldHVybiBmdW5jdGlvbiBkbyB3aGlsZSB1bnRpbCBlbHNlaWYgYmVnaW4gZm9yIHRyYXAgZGF0YSBkeW5hbWljcGFyYW0gZW5kIGJyZWFrIHRocm93IHBhcmFtIGNvbnRpbnVlIGZpbmFsbHkgaW4gc3dpdGNoIGV4aXQgZmlsdGVyIHRyeSBwcm9jZXNzIGNhdGNoVmFsaWRhdGVOb0NpcmNsZUluTm9kZVJlc291cmNlcyBWYWxpZGF0ZU5vZGVFeGNsdXNpdmVSZXNvdXJjZXMgVmFsaWRhdGVOb2RlTWFuYWdlciBWYWxpZGF0ZU5vZGVSZXNvdXJjZXMgVmFsaWRhdGVOb2RlUmVzb3VyY2VTb3VyY2UgVmFsaWRhdGVOb05hbWVOb2RlUmVzb3VyY2VzIFRocm93RXJyb3IgSXNIaWRkZW5SZXNvdXJjZUlzUGF0dGVybk1hdGNoZWQgIixidWlsdF9pbjoiQWRkLUNvbXB1dGVyIEFkZC1Db250ZW50IEFkZC1IaXN0b3J5IEFkZC1Kb2JUcmlnZ2VyIEFkZC1NZW1iZXIgQWRkLVBTU25hcGluIEFkZC1UeXBlIENoZWNrcG9pbnQtQ29tcHV0ZXIgQ2xlYXItQ29udGVudCBDbGVhci1FdmVudExvZyBDbGVhci1IaXN0b3J5IENsZWFyLUhvc3QgQ2xlYXItSXRlbSBDbGVhci1JdGVtUHJvcGVydHkgQ2xlYXItVmFyaWFibGUgQ29tcGFyZS1PYmplY3QgQ29tcGxldGUtVHJhbnNhY3Rpb24gQ29ubmVjdC1QU1Nlc3Npb24gQ29ubmVjdC1XU01hbiBDb252ZXJ0LVBhdGggQ29udmVydEZyb20tQ3N2IENvbnZlcnRGcm9tLUpzb24gQ29udmVydEZyb20tU2VjdXJlU3RyaW5nIENvbnZlcnRGcm9tLVN0cmluZ0RhdGEgQ29udmVydFRvLUNzdiBDb252ZXJ0VG8tSHRtbCBDb252ZXJ0VG8tSnNvbiBDb252ZXJ0VG8tU2VjdXJlU3RyaW5nIENvbnZlcnRUby1YbWwgQ29weS1JdGVtIENvcHktSXRlbVByb3BlcnR5IERlYnVnLVByb2Nlc3MgRGlzYWJsZS1Db21wdXRlclJlc3RvcmUgRGlzYWJsZS1Kb2JUcmlnZ2VyIERpc2FibGUtUFNCcmVha3BvaW50IERpc2FibGUtUFNSZW1vdGluZyBEaXNhYmxlLVBTU2Vzc2lvbkNvbmZpZ3VyYXRpb24gRGlzYWJsZS1XU01hbkNyZWRTU1AgRGlzY29ubmVjdC1QU1Nlc3Npb24gRGlzY29ubmVjdC1XU01hbiBEaXNhYmxlLVNjaGVkdWxlZEpvYiBFbmFibGUtQ29tcHV0ZXJSZXN0b3JlIEVuYWJsZS1Kb2JUcmlnZ2VyIEVuYWJsZS1QU0JyZWFrcG9pbnQgRW5hYmxlLVBTUmVtb3RpbmcgRW5hYmxlLVBTU2Vzc2lvbkNvbmZpZ3VyYXRpb24gRW5hYmxlLVNjaGVkdWxlZEpvYiBFbmFibGUtV1NNYW5DcmVkU1NQIEVudGVyLVBTU2Vzc2lvbiBFeGl0LVBTU2Vzc2lvbiBFeHBvcnQtQWxpYXMgRXhwb3J0LUNsaXhtbCBFeHBvcnQtQ29uc29sZSBFeHBvcnQtQ291bnRlciBFeHBvcnQtQ3N2IEV4cG9ydC1Gb3JtYXREYXRhIEV4cG9ydC1Nb2R1bGVNZW1iZXIgRXhwb3J0LVBTU2Vzc2lvbiBGb3JFYWNoLU9iamVjdCBGb3JtYXQtQ3VzdG9tIEZvcm1hdC1MaXN0IEZvcm1hdC1UYWJsZSBGb3JtYXQtV2lkZSBHZXQtQWNsIEdldC1BbGlhcyBHZXQtQXV0aGVudGljb2RlU2lnbmF0dXJlIEdldC1DaGlsZEl0ZW0gR2V0LUNvbW1hbmQgR2V0LUNvbXB1dGVyUmVzdG9yZVBvaW50IEdldC1Db250ZW50IEdldC1Db250cm9sUGFuZWxJdGVtIEdldC1Db3VudGVyIEdldC1DcmVkZW50aWFsIEdldC1DdWx0dXJlIEdldC1EYXRlIEdldC1FdmVudCBHZXQtRXZlbnRMb2cgR2V0LUV2ZW50U3Vic2NyaWJlciBHZXQtRXhlY3V0aW9uUG9saWN5IEdldC1Gb3JtYXREYXRhIEdldC1Ib3N0IEdldC1Ib3RGaXggR2V0LUhlbHAgR2V0LUhpc3RvcnkgR2V0LUlzZVNuaXBwZXQgR2V0LUl0ZW0gR2V0LUl0ZW1Qcm9wZXJ0eSBHZXQtSm9iIEdldC1Kb2JUcmlnZ2VyIEdldC1Mb2NhdGlvbiBHZXQtTWVtYmVyIEdldC1Nb2R1bGUgR2V0LVBmeENlcnRpZmljYXRlIEdldC1Qcm9jZXNzIEdldC1QU0JyZWFrcG9pbnQgR2V0LVBTQ2FsbFN0YWNrIEdldC1QU0RyaXZlIEdldC1QU1Byb3ZpZGVyIEdldC1QU1Nlc3Npb24gR2V0LVBTU2Vzc2lvbkNvbmZpZ3VyYXRpb24gR2V0LVBTU25hcGluIEdldC1SYW5kb20gR2V0LVNjaGVkdWxlZEpvYiBHZXQtU2NoZWR1bGVkSm9iT3B0aW9uIEdldC1TZXJ2aWNlIEdldC1UcmFjZVNvdXJjZSBHZXQtVHJhbnNhY3Rpb24gR2V0LVR5cGVEYXRhIEdldC1VSUN1bHR1cmUgR2V0LVVuaXF1ZSBHZXQtVmFyaWFibGUgR2V0LVZlcmIgR2V0LVdpbkV2ZW50IEdldC1XbWlPYmplY3QgR2V0LVdTTWFuQ3JlZFNTUCBHZXQtV1NNYW5JbnN0YW5jZSBHcm91cC1PYmplY3QgSW1wb3J0LUFsaWFzIEltcG9ydC1DbGl4bWwgSW1wb3J0LUNvdW50ZXIgSW1wb3J0LUNzdiBJbXBvcnQtSXNlU25pcHBldCBJbXBvcnQtTG9jYWxpemVkRGF0YSBJbXBvcnQtUFNTZXNzaW9uIEltcG9ydC1Nb2R1bGUgSW52b2tlLUFzV29ya2Zsb3cgSW52b2tlLUNvbW1hbmQgSW52b2tlLUV4cHJlc3Npb24gSW52b2tlLUhpc3RvcnkgSW52b2tlLUl0ZW0gSW52b2tlLVJlc3RNZXRob2QgSW52b2tlLVdlYlJlcXVlc3QgSW52b2tlLVdtaU1ldGhvZCBJbnZva2UtV1NNYW5BY3Rpb24gSm9pbi1QYXRoIExpbWl0LUV2ZW50TG9nIE1lYXN1cmUtQ29tbWFuZCBNZWFzdXJlLU9iamVjdCBNb3ZlLUl0ZW0gTW92ZS1JdGVtUHJvcGVydHkgTmV3LUFsaWFzIE5ldy1FdmVudCBOZXctRXZlbnRMb2cgTmV3LUlzZVNuaXBwZXQgTmV3LUl0ZW0gTmV3LUl0ZW1Qcm9wZXJ0eSBOZXctSm9iVHJpZ2dlciBOZXctT2JqZWN0IE5ldy1Nb2R1bGUgTmV3LU1vZHVsZU1hbmlmZXN0IE5ldy1QU0RyaXZlIE5ldy1QU1Nlc3Npb24gTmV3LVBTU2Vzc2lvbkNvbmZpZ3VyYXRpb25GaWxlIE5ldy1QU1Nlc3Npb25PcHRpb24gTmV3LVBTVHJhbnNwb3J0T3B0aW9uIE5ldy1QU1dvcmtmbG93RXhlY3V0aW9uT3B0aW9uIE5ldy1QU1dvcmtmbG93U2Vzc2lvbiBOZXctU2NoZWR1bGVkSm9iT3B0aW9uIE5ldy1TZXJ2aWNlIE5ldy1UaW1lU3BhbiBOZXctVmFyaWFibGUgTmV3LVdlYlNlcnZpY2VQcm94eSBOZXctV2luRXZlbnQgTmV3LVdTTWFuSW5zdGFuY2UgTmV3LVdTTWFuU2Vzc2lvbk9wdGlvbiBPdXQtRGVmYXVsdCBPdXQtRmlsZSBPdXQtR3JpZFZpZXcgT3V0LUhvc3QgT3V0LU51bGwgT3V0LVByaW50ZXIgT3V0LVN0cmluZyBQb3AtTG9jYXRpb24gUHVzaC1Mb2NhdGlvbiBSZWFkLUhvc3QgUmVjZWl2ZS1Kb2IgUmVnaXN0ZXItRW5naW5lRXZlbnQgUmVnaXN0ZXItT2JqZWN0RXZlbnQgUmVnaXN0ZXItUFNTZXNzaW9uQ29uZmlndXJhdGlvbiBSZWdpc3Rlci1TY2hlZHVsZWRKb2IgUmVnaXN0ZXItV21pRXZlbnQgUmVtb3ZlLUNvbXB1dGVyIFJlbW92ZS1FdmVudCBSZW1vdmUtRXZlbnRMb2cgUmVtb3ZlLUl0ZW0gUmVtb3ZlLUl0ZW1Qcm9wZXJ0eSBSZW1vdmUtSm9iIFJlbW92ZS1Kb2JUcmlnZ2VyIFJlbW92ZS1Nb2R1bGUgUmVtb3ZlLVBTQnJlYWtwb2ludCBSZW1vdmUtUFNEcml2ZSBSZW1vdmUtUFNTZXNzaW9uIFJlbW92ZS1QU1NuYXBpbiBSZW1vdmUtVHlwZURhdGEgUmVtb3ZlLVZhcmlhYmxlIFJlbW92ZS1XbWlPYmplY3QgUmVtb3ZlLVdTTWFuSW5zdGFuY2UgUmVuYW1lLUNvbXB1dGVyIFJlbmFtZS1JdGVtIFJlbmFtZS1JdGVtUHJvcGVydHkgUmVzZXQtQ29tcHV0ZXJNYWNoaW5lUGFzc3dvcmQgUmVzb2x2ZS1QYXRoIFJlc3RhcnQtQ29tcHV0ZXIgUmVzdGFydC1TZXJ2aWNlIFJlc3RvcmUtQ29tcHV0ZXIgUmVzdW1lLUpvYiBSZXN1bWUtU2VydmljZSBTYXZlLUhlbHAgU2VsZWN0LU9iamVjdCBTZWxlY3QtU3RyaW5nIFNlbGVjdC1YbWwgU2VuZC1NYWlsTWVzc2FnZSBTZXQtQWNsIFNldC1BbGlhcyBTZXQtQXV0aGVudGljb2RlU2lnbmF0dXJlIFNldC1Db250ZW50IFNldC1EYXRlIFNldC1FeGVjdXRpb25Qb2xpY3kgU2V0LUl0ZW0gU2V0LUl0ZW1Qcm9wZXJ0eSBTZXQtSm9iVHJpZ2dlciBTZXQtTG9jYXRpb24gU2V0LVBTQnJlYWtwb2ludCBTZXQtUFNEZWJ1ZyBTZXQtUFNTZXNzaW9uQ29uZmlndXJhdGlvbiBTZXQtU2NoZWR1bGVkSm9iIFNldC1TY2hlZHVsZWRKb2JPcHRpb24gU2V0LVNlcnZpY2UgU2V0LVN0cmljdE1vZGUgU2V0LVRyYWNlU291cmNlIFNldC1WYXJpYWJsZSBTZXQtV21pSW5zdGFuY2UgU2V0LVdTTWFuSW5zdGFuY2UgU2V0LVdTTWFuUXVpY2tDb25maWcgU2hvdy1Db21tYW5kIFNob3ctQ29udHJvbFBhbmVsSXRlbSBTaG93LUV2ZW50TG9nIFNvcnQtT2JqZWN0IFNwbGl0LVBhdGggU3RhcnQtSm9iIFN0YXJ0LVByb2Nlc3MgU3RhcnQtU2VydmljZSBTdGFydC1TbGVlcCBTdGFydC1UcmFuc2FjdGlvbiBTdGFydC1UcmFuc2NyaXB0IFN0b3AtQ29tcHV0ZXIgU3RvcC1Kb2IgU3RvcC1Qcm9jZXNzIFN0b3AtU2VydmljZSBTdG9wLVRyYW5zY3JpcHQgU3VzcGVuZC1Kb2IgU3VzcGVuZC1TZXJ2aWNlIFRlZS1PYmplY3QgVGVzdC1Db21wdXRlclNlY3VyZUNoYW5uZWwgVGVzdC1Db25uZWN0aW9uIFRlc3QtTW9kdWxlTWFuaWZlc3QgVGVzdC1QYXRoIFRlc3QtUFNTZXNzaW9uQ29uZmlndXJhdGlvbkZpbGUgVHJhY2UtQ29tbWFuZCBVbmJsb2NrLUZpbGUgVW5kby1UcmFuc2FjdGlvbiBVbnJlZ2lzdGVyLUV2ZW50IFVucmVnaXN0ZXItUFNTZXNzaW9uQ29uZmlndXJhdGlvbiBVbnJlZ2lzdGVyLVNjaGVkdWxlZEpvYiBVcGRhdGUtRm9ybWF0RGF0YSBVcGRhdGUtSGVscCBVcGRhdGUtTGlzdCBVcGRhdGUtVHlwZURhdGEgVXNlLVRyYW5zYWN0aW9uIFdhaXQtRXZlbnQgV2FpdC1Kb2IgV2FpdC1Qcm9jZXNzIFdoZXJlLU9iamVjdCBXcml0ZS1EZWJ1ZyBXcml0ZS1FcnJvciBXcml0ZS1FdmVudExvZyBXcml0ZS1Ib3N0IFdyaXRlLU91dHB1dCBXcml0ZS1Qcm9ncmVzcyBXcml0ZS1WZXJib3NlIFdyaXRlLVdhcm5pbmcgQWRkLU1EVFBlcnNpc3RlbnREcml2ZSBEaXNhYmxlLU1EVE1vbml0b3JTZXJ2aWNlIEVuYWJsZS1NRFRNb25pdG9yU2VydmljZSBHZXQtTURURGVwbG95bWVudFNoYXJlU3RhdGlzdGljcyBHZXQtTURUTW9uaXRvckRhdGEgR2V0LU1EVE9wZXJhdGluZ1N5c3RlbUNhdGFsb2cgR2V0LU1EVFBlcnNpc3RlbnREcml2ZSBJbXBvcnQtTURUQXBwbGljYXRpb24gSW1wb3J0LU1EVERyaXZlciBJbXBvcnQtTURUT3BlcmF0aW5nU3lzdGVtIEltcG9ydC1NRFRQYWNrYWdlIEltcG9ydC1NRFRUYXNrU2VxdWVuY2UgTmV3LU1EVERhdGFiYXNlIFJlbW92ZS1NRFRNb25pdG9yRGF0YSBSZW1vdmUtTURUUGVyc2lzdGVudERyaXZlIFJlc3RvcmUtTURUUGVyc2lzdGVudERyaXZlIFNldC1NRFRNb25pdG9yRGF0YSBUZXN0LU1EVERlcGxveW1lbnRTaGFyZSBUZXN0LU1EVE1vbml0b3JEYXRhIFVwZGF0ZS1NRFREYXRhYmFzZVNjaGVtYSBVcGRhdGUtTURURGVwbG95bWVudFNoYXJlIFVwZGF0ZS1NRFRMaW5rZWREUyBVcGRhdGUtTURUTWVkaWEgQWRkLVZhbXRQcm9kdWN0S2V5IEV4cG9ydC1WYW10RGF0YSBGaW5kLVZhbXRNYW5hZ2VkTWFjaGluZSBHZXQtVmFtdENvbmZpcm1hdGlvbklkIEdldC1WYW10UHJvZHVjdCBHZXQtVmFtdFByb2R1Y3RLZXkgSW1wb3J0LVZhbXREYXRhIEluaXRpYWxpemUtVmFtdERhdGEgSW5zdGFsbC1WYW10Q29uZmlybWF0aW9uSWQgSW5zdGFsbC1WYW10UHJvZHVjdEFjdGl2YXRpb24gSW5zdGFsbC1WYW10UHJvZHVjdEtleSBVcGRhdGUtVmFtdFByb2R1Y3QgQWRkLUNJRGF0YXN0b3JlIEFkZC1LZXlNYW5hZ2VtZW50U2VydmVyIEFkZC1Ob2RlS2V5cyBBZGQtTnN4RHluYW1pY0NyaXRlcmlhIEFkZC1Oc3hEeW5hbWljTWVtYmVyU2V0IEFkZC1Oc3hFZGdlSW50ZXJmYWNlQWRkcmVzcyBBZGQtTnN4RmlyZXdhbGxFeGNsdXNpb25MaXN0TWVtYmVyIEFkZC1Oc3hGaXJld2FsbFJ1bGVNZW1iZXIgQWRkLU5zeElwU2V0TWVtYmVyIEFkZC1Oc3hMaWNlbnNlIEFkZC1Oc3hMb2FkQmFsYW5jZXJQb29sTWVtYmVyIEFkZC1Oc3hMb2FkQmFsYW5jZXJWaXAgQWRkLU5zeFNlY29uZGFyeU1hbmFnZXIgQWRkLU5zeFNlY3VyaXR5R3JvdXBNZW1iZXIgQWRkLU5zeFNlY3VyaXR5UG9saWN5UnVsZSBBZGQtTnN4U2VjdXJpdHlQb2xpY3lSdWxlR3JvdXAgQWRkLU5zeFNlY3VyaXR5UG9saWN5UnVsZVNlcnZpY2UgQWRkLU5zeFNlcnZpY2VHcm91cE1lbWJlciBBZGQtTnN4VHJhbnNwb3J0Wm9uZU1lbWJlciBBZGQtUGFzc3Rocm91Z2hEZXZpY2UgQWRkLVZEU3dpdGNoUGh5c2ljYWxOZXR3b3JrQWRhcHRlciBBZGQtVkRTd2l0Y2hWTUhvc3QgQWRkLVZNSG9zdCBBZGQtVk1Ib3N0TnRwU2VydmVyIEFkZC1WaXJ0dWFsU3dpdGNoUGh5c2ljYWxOZXR3b3JrQWRhcHRlciBBZGQtWG1sRWxlbWVudCBBZGQtdlJBQ3VzdG9tRm9ybSBBZGQtdlJBUHJpbmNpcGFsVG9UZW5hbnRSb2xlIEFkZC12UkFSZXNlcnZhdGlvbk5ldHdvcmsgQWRkLXZSQVJlc2VydmF0aW9uU3RvcmFnZSBDbGVhci1Oc3hFZGdlSW50ZXJmYWNlIENsZWFyLU5zeE1hbmFnZXJUaW1lU2V0dGluZ3MgQ29tcHJlc3MtQXJjaGl2ZSBDb25uZWN0LUNJU2VydmVyIENvbm5lY3QtQ2lzU2VydmVyIENvbm5lY3QtSENYU2VydmVyIENvbm5lY3QtTklTZXJ2ZXIgQ29ubmVjdC1Oc3hMb2dpY2FsU3dpdGNoIENvbm5lY3QtTnN4U2VydmVyIENvbm5lY3QtTnN4dFNlcnZlciBDb25uZWN0LVNybVNlcnZlciBDb25uZWN0LVZJU2VydmVyIENvbm5lY3QtVm1jIENvbm5lY3QtdlJBU2VydmVyIENvbm5lY3QtdlJOSVNlcnZlciBDb252ZXJ0RnJvbS1NYXJrZG93biBDb252ZXJ0VG8tTU9GSW5zdGFuY2UgQ29weS1EYXRhc3RvcmVJdGVtIENvcHktSGFyZERpc2sgQ29weS1Oc3hFZGdlIENvcHktVkRpc2sgQ29weS1WTUd1ZXN0RmlsZSBEZWJ1Zy1SdW5zcGFjZSBEaXNhYmxlLU5zeEVkZ2VTc2ggRGlzYWJsZS1SdW5zcGFjZURlYnVnIERpc2FibGUtdlJOSURhdGFTb3VyY2UgRGlzY29ubmVjdC1DSVNlcnZlciBEaXNjb25uZWN0LUNpc1NlcnZlciBEaXNjb25uZWN0LUhDWFNlcnZlciBEaXNjb25uZWN0LU5zeExvZ2ljYWxTd2l0Y2ggRGlzY29ubmVjdC1Oc3hTZXJ2ZXIgRGlzY29ubmVjdC1Oc3h0U2VydmVyIERpc2Nvbm5lY3QtU3JtU2VydmVyIERpc2Nvbm5lY3QtVklTZXJ2ZXIgRGlzY29ubmVjdC1WbWMgRGlzY29ubmVjdC12UkFTZXJ2ZXIgRGlzY29ubmVjdC12Uk5JU2VydmVyIERpc21vdW50LVRvb2xzIEVuYWJsZS1Oc3hFZGdlU3NoIEVuYWJsZS1SdW5zcGFjZURlYnVnIEVuYWJsZS12Uk5JRGF0YVNvdXJjZSBFeHBhbmQtQXJjaGl2ZSBFeHBvcnQtTnN4T2JqZWN0IEV4cG9ydC1TcGJtU3RvcmFnZVBvbGljeSBFeHBvcnQtVkFwcCBFeHBvcnQtVkRQb3J0R3JvdXAgRXhwb3J0LVZEU3dpdGNoIEV4cG9ydC1WTUhvc3RQcm9maWxlIEV4cG9ydC12UkFJY29uIEV4cG9ydC12UkFQYWNrYWdlIEZpbmQtQ29tbWFuZCBGaW5kLURzY1Jlc291cmNlIEZpbmQtTW9kdWxlIEZpbmQtTnN4V2hlcmVWTVVzZWQgRmluZC1QYWNrYWdlIEZpbmQtUGFja2FnZVByb3ZpZGVyIEZpbmQtUm9sZUNhcGFiaWxpdHkgRmluZC1TY3JpcHQgRm9ybWF0LUhleCBGb3JtYXQtVk1Ib3N0RGlza1BhcnRpdGlvbiBGb3JtYXQtWE1MIEdlbmVyYXRlLVZlcnNpb25JbmZvIEdldC1BZHZhbmNlZFNldHRpbmcgR2V0LUFsYXJtQWN0aW9uIEdldC1BbGFybUFjdGlvblRyaWdnZXIgR2V0LUFsYXJtRGVmaW5pdGlvbiBHZXQtQW5ub3RhdGlvbiBHZXQtQ0REcml2ZSBHZXQtQ0lBY2Nlc3NDb250cm9sUnVsZSBHZXQtQ0lEYXRhc3RvcmUgR2V0LUNJTmV0d29ya0FkYXB0ZXIgR2V0LUNJUm9sZSBHZXQtQ0lVc2VyIEdldC1DSVZBcHAgR2V0LUNJVkFwcE5ldHdvcmsgR2V0LUNJVkFwcFN0YXJ0UnVsZSBHZXQtQ0lWQXBwVGVtcGxhdGUgR2V0LUNJVk0gR2V0LUNJVk1UZW1wbGF0ZSBHZXQtQ0lWaWV3IEdldC1DYXRhbG9nIEdldC1DaXNDb21tYW5kIEdldC1DaXNTZXJ2aWNlIEdldC1DbG91ZENvbW1hbmQgR2V0LUNsdXN0ZXIgR2V0LUNvbXBhdGlibGVWZXJzaW9uQWRkdGlvbmFQcm9wZXJ0aWVzU3RyIEdldC1Db21wbGV4UmVzb3VyY2VRdWFsaWZpZXIgR2V0LUNvbmZpZ3VyYXRpb25FcnJvckNvdW50IEdldC1Db250ZW50TGlicmFyeUl0ZW0gR2V0LUN1c3RvbUF0dHJpYnV0ZSBHZXQtRFNDUmVzb3VyY2VNb2R1bGVzIEdldC1EYXRhY2VudGVyIEdldC1EYXRhc3RvcmUgR2V0LURhdGFzdG9yZUNsdXN0ZXIgR2V0LURyc0NsdXN0ZXJHcm91cCBHZXQtRHJzUmVjb21tZW5kYXRpb24gR2V0LURyc1J1bGUgR2V0LURyc1ZNSG9zdFJ1bGUgR2V0LURzY1Jlc291cmNlIEdldC1FZGdlR2F0ZXdheSBHZXQtRW5jcnlwdGVkUGFzc3dvcmQgR2V0LUVycm9yUmVwb3J0IEdldC1Fc3hDbGkgR2V0LUVzeFRvcCBHZXQtRXh0ZXJuYWxOZXR3b3JrIEdldC1GaWxlSGFzaCBHZXQtRmxvcHB5RHJpdmUgR2V0LUZvbGRlciBHZXQtSEFQcmltYXJ5Vk1Ib3N0IEdldC1IQ1hBcHBsaWFuY2UgR2V0LUhDWEFwcGxpYW5jZUNvbXB1dGUgR2V0LUhDWEFwcGxpYW5jZURWUyBHZXQtSENYQXBwbGlhbmNlRGF0YXN0b3JlIEdldC1IQ1hBcHBsaWFuY2VOZXR3b3JrIEdldC1IQ1hDb250YWluZXIgR2V0LUhDWERhdGFzdG9yZSBHZXQtSENYR2F0ZXdheSBHZXQtSENYSW50ZXJjb25uZWN0U3RhdHVzIEdldC1IQ1hKb2IgR2V0LUhDWE1pZ3JhdGlvbiBHZXQtSENYTmV0d29yayBHZXQtSENYTmV0d29ya0V4dGVuc2lvbiBHZXQtSENYUmVwbGljYXRpb24gR2V0LUhDWFJlcGxpY2F0aW9uU25hcHNob3QgR2V0LUhDWFNlcnZpY2UgR2V0LUhDWFNpdGUgR2V0LUhDWFNpdGVQYWlyaW5nIEdldC1IQ1hWTSBHZXQtSGFyZERpc2sgR2V0LUlTY3NpSGJhVGFyZ2V0IEdldC1Jbm5lck1vc3RFcnJvclJlY29yZCBHZXQtSW5zdGFsbFBhdGggR2V0LUluc3RhbGxlZE1vZHVsZSBHZXQtSW5zdGFsbGVkU2NyaXB0IEdldC1JbnZlbnRvcnkgR2V0LUl0ZW1Qcm9wZXJ0eVZhbHVlIEdldC1LZXlNYW5hZ2VtZW50U2VydmVyIEdldC1LbWlwQ2xpZW50Q2VydGlmaWNhdGUgR2V0LUttc0NsdXN0ZXIgR2V0LUxvZyBHZXQtTG9nVHlwZSBHZXQtTWFya2Rvd25PcHRpb24gR2V0LU1lZGlhIEdldC1Nb2ZJbnN0YW5jZU5hbWUgR2V0LU1vZkluc3RhbmNlVGV4dCBHZXQtTmV0d29ya0FkYXB0ZXIgR2V0LU5ldHdvcmtQb29sIEdldC1OZnNVc2VyIEdldC1OaWNUZWFtaW5nUG9saWN5IEdldC1Oc3hBcHBsaWNhYmxlTWVtYmVyIEdldC1Oc3hBcHBsaWNhYmxlU2VjdXJpdHlBY3Rpb24gR2V0LU5zeEJhY2tpbmdEVlN3aXRjaCBHZXQtTnN4QmFja2luZ1BvcnRHcm91cCBHZXQtTnN4Q2xpRGZ3QWRkclNldCBHZXQtTnN4Q2xpRGZ3RmlsdGVyIEdldC1Oc3hDbGlEZndSdWxlIEdldC1Oc3hDbHVzdGVyU3RhdHVzIEdldC1Oc3hDb250cm9sbGVyIEdldC1Oc3hEeW5hbWljQ3JpdGVyaWEgR2V0LU5zeER5bmFtaWNNZW1iZXJTZXQgR2V0LU5zeEVkZ2UgR2V0LU5zeEVkZ2VCZ3AgR2V0LU5zeEVkZ2VCZ3BOZWlnaGJvdXIgR2V0LU5zeEVkZ2VDZXJ0aWZpY2F0ZSBHZXQtTnN4RWRnZUNzciBHZXQtTnN4RWRnZUZpcmV3YWxsIEdldC1Oc3hFZGdlRmlyZXdhbGxSdWxlIEdldC1Oc3hFZGdlSW50ZXJmYWNlIEdldC1Oc3hFZGdlSW50ZXJmYWNlQWRkcmVzcyBHZXQtTnN4RWRnZU5hdCBHZXQtTnN4RWRnZU5hdFJ1bGUgR2V0LU5zeEVkZ2VPc3BmIEdldC1Oc3hFZGdlT3NwZkFyZWEgR2V0LU5zeEVkZ2VPc3BmSW50ZXJmYWNlIEdldC1Oc3hFZGdlUHJlZml4IEdldC1Oc3hFZGdlUmVkaXN0cmlidXRpb25SdWxlIEdldC1Oc3hFZGdlUm91dGluZyBHZXQtTnN4RWRnZVN0YXRpY1JvdXRlIEdldC1Oc3hFZGdlU3ViSW50ZXJmYWNlIEdldC1Oc3hGaXJld2FsbEV4Y2x1c2lvbkxpc3RNZW1iZXIgR2V0LU5zeEZpcmV3YWxsR2xvYmFsQ29uZmlndXJhdGlvbiBHZXQtTnN4RmlyZXdhbGxQdWJsaXNoU3RhdHVzIEdldC1Oc3hGaXJld2FsbFJ1bGUgR2V0LU5zeEZpcmV3YWxsUnVsZU1lbWJlciBHZXQtTnN4RmlyZXdhbGxTYXZlZENvbmZpZ3VyYXRpb24gR2V0LU5zeEZpcmV3YWxsU2VjdGlvbiBHZXQtTnN4RmlyZXdhbGxUaHJlc2hvbGQgR2V0LU5zeElwUG9vbCBHZXQtTnN4SXBTZXQgR2V0LU5zeExpY2Vuc2UgR2V0LU5zeExvYWRCYWxhbmNlciBHZXQtTnN4TG9hZEJhbGFuY2VyQXBwbGljYXRpb25Qcm9maWxlIEdldC1Oc3hMb2FkQmFsYW5jZXJBcHBsaWNhdGlvblJ1bGUgR2V0LU5zeExvYWRCYWxhbmNlck1vbml0b3IgR2V0LU5zeExvYWRCYWxhbmNlclBvb2wgR2V0LU5zeExvYWRCYWxhbmNlclBvb2xNZW1iZXIgR2V0LU5zeExvYWRCYWxhbmNlclN0YXRzIEdldC1Oc3hMb2FkQmFsYW5jZXJWaXAgR2V0LU5zeExvZ2ljYWxSb3V0ZXIgR2V0LU5zeExvZ2ljYWxSb3V0ZXJCZ3AgR2V0LU5zeExvZ2ljYWxSb3V0ZXJCZ3BOZWlnaGJvdXIgR2V0LU5zeExvZ2ljYWxSb3V0ZXJCcmlkZ2UgR2V0LU5zeExvZ2ljYWxSb3V0ZXJCcmlkZ2luZyBHZXQtTnN4TG9naWNhbFJvdXRlckludGVyZmFjZSBHZXQtTnN4TG9naWNhbFJvdXRlck9zcGYgR2V0LU5zeExvZ2ljYWxSb3V0ZXJPc3BmQXJlYSBHZXQtTnN4TG9naWNhbFJvdXRlck9zcGZJbnRlcmZhY2UgR2V0LU5zeExvZ2ljYWxSb3V0ZXJQcmVmaXggR2V0LU5zeExvZ2ljYWxSb3V0ZXJSZWRpc3RyaWJ1dGlvblJ1bGUgR2V0LU5zeExvZ2ljYWxSb3V0ZXJSb3V0aW5nIEdldC1Oc3hMb2dpY2FsUm91dGVyU3RhdGljUm91dGUgR2V0LU5zeExvZ2ljYWxTd2l0Y2ggR2V0LU5zeE1hY1NldCBHZXQtTnN4TWFuYWdlckJhY2t1cCBHZXQtTnN4TWFuYWdlckNlcnRpZmljYXRlIEdldC1Oc3hNYW5hZ2VyQ29tcG9uZW50U3VtbWFyeSBHZXQtTnN4TWFuYWdlck5ldHdvcmsgR2V0LU5zeE1hbmFnZXJSb2xlIEdldC1Oc3hNYW5hZ2VyU3NvQ29uZmlnIEdldC1Oc3hNYW5hZ2VyU3luY1N0YXR1cyBHZXQtTnN4TWFuYWdlclN5c2xvZ1NlcnZlciBHZXQtTnN4TWFuYWdlclN5c3RlbVN1bW1hcnkgR2V0LU5zeE1hbmFnZXJUaW1lU2V0dGluZ3MgR2V0LU5zeE1hbmFnZXJWY2VudGVyQ29uZmlnIEdldC1Oc3hTZWNvbmRhcnlNYW5hZ2VyIEdldC1Oc3hTZWN1cml0eUdyb3VwIEdldC1Oc3hTZWN1cml0eUdyb3VwRWZmZWN0aXZlSXBBZGRyZXNzIEdldC1Oc3hTZWN1cml0eUdyb3VwRWZmZWN0aXZlTWFjQWRkcmVzcyBHZXQtTnN4U2VjdXJpdHlHcm91cEVmZmVjdGl2ZU1lbWJlciBHZXQtTnN4U2VjdXJpdHlHcm91cEVmZmVjdGl2ZVZpcnR1YWxNYWNoaW5lIEdldC1Oc3hTZWN1cml0eUdyb3VwRWZmZWN0aXZlVm5pYyBHZXQtTnN4U2VjdXJpdHlHcm91cE1lbWJlclR5cGVzIEdldC1Oc3hTZWN1cml0eVBvbGljeSBHZXQtTnN4U2VjdXJpdHlQb2xpY3lIaWdoZXN0VXNlZFByZWNlZGVuY2UgR2V0LU5zeFNlY3VyaXR5UG9saWN5UnVsZSBHZXQtTnN4U2VjdXJpdHlUYWcgR2V0LU5zeFNlY3VyaXR5VGFnQXNzaWdubWVudCBHZXQtTnN4U2VnbWVudElkUmFuZ2UgR2V0LU5zeFNlcnZpY2UgR2V0LU5zeFNlcnZpY2VEZWZpbml0aW9uIEdldC1Oc3hTZXJ2aWNlR3JvdXAgR2V0LU5zeFNlcnZpY2VHcm91cE1lbWJlciBHZXQtTnN4U2VydmljZVByb2ZpbGUgR2V0LU5zeFNwb29mZ3VhcmROaWMgR2V0LU5zeFNwb29mZ3VhcmRQb2xpY3kgR2V0LU5zeFNzbFZwbiBHZXQtTnN4U3NsVnBuQXV0aFNlcnZlciBHZXQtTnN4U3NsVnBuQ2xpZW50SW5zdGFsbGF0aW9uUGFja2FnZSBHZXQtTnN4U3NsVnBuSXBQb29sIEdldC1Oc3hTc2xWcG5Qcml2YXRlTmV0d29yayBHZXQtTnN4U3NsVnBuVXNlciBHZXQtTnN4VHJhbnNwb3J0Wm9uZSBHZXQtTnN4VXNlclJvbGUgR2V0LU5zeFZkc0NvbnRleHQgR2V0LU5zeHRQb2xpY3lTZXJ2aWNlIEdldC1Oc3h0U2VydmljZSBHZXQtT1NDdXN0b21pemF0aW9uTmljTWFwcGluZyBHZXQtT1NDdXN0b21pemF0aW9uU3BlYyBHZXQtT3JnIEdldC1PcmdOZXR3b3JrIEdldC1PcmdWZGMgR2V0LU9yZ1ZkY05ldHdvcmsgR2V0LU92ZkNvbmZpZ3VyYXRpb24gR2V0LVBTQ3VycmVudENvbmZpZ3VyYXRpb25Ob2RlIEdldC1QU0RlZmF1bHRDb25maWd1cmF0aW9uRG9jdW1lbnQgR2V0LVBTTWV0YUNvbmZpZ0RvY3VtZW50SW5zdFZlcnNpb25JbmZvIEdldC1QU01ldGFDb25maWd1cmF0aW9uUHJvY2Vzc2VkIEdldC1QU1JlYWRMaW5lS2V5SGFuZGxlciBHZXQtUFNSZWFkTGluZU9wdGlvbiBHZXQtUFNSZXBvc2l0b3J5IEdldC1QU1RvcENvbmZpZ3VyYXRpb25OYW1lIEdldC1QU1ZlcnNpb24gR2V0LVBhY2thZ2UgR2V0LVBhY2thZ2VQcm92aWRlciBHZXQtUGFja2FnZVNvdXJjZSBHZXQtUGFzc3Rocm91Z2hEZXZpY2UgR2V0LVBvc2l0aW9uSW5mbyBHZXQtUG93ZXJDTElDb21tdW5pdHkgR2V0LVBvd2VyQ0xJQ29uZmlndXJhdGlvbiBHZXQtUG93ZXJDTElIZWxwIEdldC1Qb3dlckNMSVZlcnNpb24gR2V0LVBvd2VyTnN4VmVyc2lvbiBHZXQtUHJvdmlkZXJWZGMgR2V0LVB1YmxpY0tleUZyb21GaWxlIEdldC1QdWJsaWNLZXlGcm9tU3RvcmUgR2V0LVJlc291cmNlUG9vbCBHZXQtUnVuc3BhY2UgR2V0LVJ1bnNwYWNlRGVidWcgR2V0LVNjc2lDb250cm9sbGVyIEdldC1TY3NpTHVuIEdldC1TY3NpTHVuUGF0aCBHZXQtU2VjdXJpdHlJbmZvIEdldC1TZWN1cml0eVBvbGljeSBHZXQtU25hcHNob3QgR2V0LVNwYm1DYXBhYmlsaXR5IEdldC1TcGJtQ29tcGF0aWJsZVN0b3JhZ2UgR2V0LVNwYm1FbnRpdHlDb25maWd1cmF0aW9uIEdldC1TcGJtRmF1bHREb21haW4gR2V0LVNwYm1Qb2ludEluVGltZVJlcGxpY2EgR2V0LVNwYm1SZXBsaWNhdGlvbkdyb3VwIEdldC1TcGJtUmVwbGljYXRpb25QYWlyIEdldC1TcGJtU3RvcmFnZVBvbGljeSBHZXQtU3RhdCBHZXQtU3RhdEludGVydmFsIEdldC1TdGF0VHlwZSBHZXQtVGFnIEdldC1UYWdBc3NpZ25tZW50IEdldC1UYWdDYXRlZ29yeSBHZXQtVGFzayBHZXQtVGVtcGxhdGUgR2V0LVRpbWVab25lIEdldC1VcHRpbWUgR2V0LVVzYkRldmljZSBHZXQtVkFJT0ZpbHRlciBHZXQtVkFwcCBHZXQtVkRCbG9ja2VkUG9saWN5IEdldC1WRFBvcnQgR2V0LVZEUG9ydGdyb3VwIEdldC1WRFBvcnRncm91cE92ZXJyaWRlUG9saWN5IEdldC1WRFNlY3VyaXR5UG9saWN5IEdldC1WRFN3aXRjaCBHZXQtVkRTd2l0Y2hQcml2YXRlVmxhbiBHZXQtVkRUcmFmZmljU2hhcGluZ1BvbGljeSBHZXQtVkRVcGxpbmtMYWNwUG9saWN5IEdldC1WRFVwbGlua1RlYW1pbmdQb2xpY3kgR2V0LVZEaXNrIEdldC1WSUFjY291bnQgR2V0LVZJQ29tbWFuZCBHZXQtVklDcmVkZW50aWFsU3RvcmVJdGVtIEdldC1WSUV2ZW50IEdldC1WSU9iamVjdEJ5VklWaWV3IEdldC1WSVBlcm1pc3Npb24gR2V0LVZJUHJpdmlsZWdlIEdldC1WSVByb3BlcnR5IEdldC1WSVJvbGUgR2V0LVZNIEdldC1WTUd1ZXN0IEdldC1WTUhvc3QgR2V0LVZNSG9zdEFjY291bnQgR2V0LVZNSG9zdEFkdmFuY2VkQ29uZmlndXJhdGlvbiBHZXQtVk1Ib3N0QXV0aGVudGljYXRpb24gR2V0LVZNSG9zdEF2YWlsYWJsZVRpbWVab25lIEdldC1WTUhvc3REaWFnbm9zdGljUGFydGl0aW9uIEdldC1WTUhvc3REaXNrIEdldC1WTUhvc3REaXNrUGFydGl0aW9uIEdldC1WTUhvc3RGaXJld2FsbERlZmF1bHRQb2xpY3kgR2V0LVZNSG9zdEZpcmV3YWxsRXhjZXB0aW9uIEdldC1WTUhvc3RGaXJtd2FyZSBHZXQtVk1Ib3N0SGFyZHdhcmUgR2V0LVZNSG9zdEhiYSBHZXQtVk1Ib3N0TW9kdWxlIEdldC1WTUhvc3ROZXR3b3JrIEdldC1WTUhvc3ROZXR3b3JrQWRhcHRlciBHZXQtVk1Ib3N0TnRwU2VydmVyIEdldC1WTUhvc3RQYXRjaCBHZXQtVk1Ib3N0UGNpRGV2aWNlIEdldC1WTUhvc3RQcm9maWxlIEdldC1WTUhvc3RQcm9maWxlSW1hZ2VDYWNoZUNvbmZpZ3VyYXRpb24gR2V0LVZNSG9zdFByb2ZpbGVSZXF1aXJlZElucHV0IEdldC1WTUhvc3RQcm9maWxlU3RvcmFnZURldmljZUNvbmZpZ3VyYXRpb24gR2V0LVZNSG9zdFByb2ZpbGVVc2VyQ29uZmlndXJhdGlvbiBHZXQtVk1Ib3N0UHJvZmlsZVZtUG9ydEdyb3VwQ29uZmlndXJhdGlvbiBHZXQtVk1Ib3N0Um91dGUgR2V0LVZNSG9zdFNlcnZpY2UgR2V0LVZNSG9zdFNubXAgR2V0LVZNSG9zdFN0YXJ0UG9saWN5IEdldC1WTUhvc3RTdG9yYWdlIEdldC1WTUhvc3RTeXNMb2dTZXJ2ZXIgR2V0LVZNUXVlc3Rpb24gR2V0LVZNUmVzb3VyY2VDb25maWd1cmF0aW9uIEdldC1WTVN0YXJ0UG9saWN5IEdldC1WVHBtIEdldC1WVHBtQ1NSIEdldC1WVHBtQ2VydGlmaWNhdGUgR2V0LVZhc2FQcm92aWRlciBHZXQtVmFzYVN0b3JhZ2VBcnJheSBHZXQtVmlldyBHZXQtVmlydHVhbFBvcnRHcm91cCBHZXQtVmlydHVhbFN3aXRjaCBHZXQtVm1jU2RkY05ldHdvcmtTZXJ2aWNlIEdldC1WbWNTZXJ2aWNlIEdldC1Wc2FuQ2x1c3RlckNvbmZpZ3VyYXRpb24gR2V0LVZzYW5Db21wb25lbnQgR2V0LVZzYW5EaXNrIEdldC1Wc2FuRGlza0dyb3VwIEdldC1Wc2FuRXZhY3VhdGlvblBsYW4gR2V0LVZzYW5GYXVsdERvbWFpbiBHZXQtVnNhbklzY3NpSW5pdGlhdG9yR3JvdXAgR2V0LVZzYW5Jc2NzaUluaXRpYXRvckdyb3VwVGFyZ2V0QXNzb2NpYXRpb24gR2V0LVZzYW5Jc2NzaUx1biBHZXQtVnNhbklzY3NpVGFyZ2V0IEdldC1Wc2FuT2JqZWN0IEdldC1Wc2FuUmVzeW5jaW5nQ29tcG9uZW50IEdldC1Wc2FuUnVudGltZUluZm8gR2V0LVZzYW5TcGFjZVVzYWdlIEdldC1Wc2FuU3RhdCBHZXQtVnNhblZpZXcgR2V0LXZSQUFwcGxpYW5jZVNlcnZpY2VTdGF0dXMgR2V0LXZSQUF1dGhvcml6YXRpb25Sb2xlIEdldC12UkFCbHVlcHJpbnQgR2V0LXZSQUJ1c2luZXNzR3JvdXAgR2V0LXZSQUNhdGFsb2dJdGVtIEdldC12UkFDYXRhbG9nSXRlbVJlcXVlc3RUZW1wbGF0ZSBHZXQtdlJBQ2F0YWxvZ1ByaW5jaXBhbCBHZXQtdlJBQ29tcG9uZW50UmVnaXN0cnlTZXJ2aWNlIEdldC12UkFDb21wb25lbnRSZWdpc3RyeVNlcnZpY2VFbmRwb2ludCBHZXQtdlJBQ29tcG9uZW50UmVnaXN0cnlTZXJ2aWNlU3RhdHVzIEdldC12UkFDb250ZW50IEdldC12UkFDb250ZW50RGF0YSBHZXQtdlJBQ29udGVudFR5cGUgR2V0LXZSQUN1c3RvbUZvcm0gR2V0LXZSQUVudGl0bGVkQ2F0YWxvZ0l0ZW0gR2V0LXZSQUVudGl0bGVkU2VydmljZSBHZXQtdlJBRW50aXRsZW1lbnQgR2V0LXZSQUV4dGVybmFsTmV0d29ya1Byb2ZpbGUgR2V0LXZSQUdyb3VwUHJpbmNpcGFsIEdldC12UkFJY29uIEdldC12UkFOQVROZXR3b3JrUHJvZmlsZSBHZXQtdlJBTmV0d29ya1Byb2ZpbGVJUEFkZHJlc3NMaXN0IEdldC12UkFOZXR3b3JrUHJvZmlsZUlQUmFuZ2VTdW1tYXJ5IEdldC12UkFQYWNrYWdlIEdldC12UkFQYWNrYWdlQ29udGVudCBHZXQtdlJBUHJvcGVydHlEZWZpbml0aW9uIEdldC12UkFQcm9wZXJ0eUdyb3VwIEdldC12UkFSZXF1ZXN0IEdldC12UkFSZXF1ZXN0RGV0YWlsIEdldC12UkFSZXNlcnZhdGlvbiBHZXQtdlJBUmVzZXJ2YXRpb25Db21wdXRlUmVzb3VyY2UgR2V0LXZSQVJlc2VydmF0aW9uQ29tcHV0ZVJlc291cmNlTWVtb3J5IEdldC12UkFSZXNlcnZhdGlvbkNvbXB1dGVSZXNvdXJjZU5ldHdvcmsgR2V0LXZSQVJlc2VydmF0aW9uQ29tcHV0ZVJlc291cmNlUmVzb3VyY2VQb29sIEdldC12UkFSZXNlcnZhdGlvbkNvbXB1dGVSZXNvdXJjZVN0b3JhZ2UgR2V0LXZSQVJlc2VydmF0aW9uUG9saWN5IEdldC12UkFSZXNlcnZhdGlvblRlbXBsYXRlIEdldC12UkFSZXNlcnZhdGlvblR5cGUgR2V0LXZSQVJlc291cmNlIEdldC12UkFSZXNvdXJjZUFjdGlvbiBHZXQtdlJBUmVzb3VyY2VBY3Rpb25SZXF1ZXN0VGVtcGxhdGUgR2V0LXZSQVJlc291cmNlTWV0cmljIEdldC12UkFSZXNvdXJjZU9wZXJhdGlvbiBHZXQtdlJBUmVzb3VyY2VUeXBlIEdldC12UkFSb3V0ZWROZXR3b3JrUHJvZmlsZSBHZXQtdlJBU2VydmljZSBHZXQtdlJBU2VydmljZUJsdWVwcmludCBHZXQtdlJBU291cmNlTWFjaGluZSBHZXQtdlJBU3RvcmFnZVJlc2VydmF0aW9uUG9saWN5IEdldC12UkFUZW5hbnQgR2V0LXZSQVRlbmFudERpcmVjdG9yeSBHZXQtdlJBVGVuYW50RGlyZWN0b3J5U3RhdHVzIEdldC12UkFUZW5hbnRSb2xlIEdldC12UkFVc2VyUHJpbmNpcGFsIEdldC12UkFVc2VyUHJpbmNpcGFsR3JvdXBNZW1iZXJzaGlwIEdldC12UkFWZXJzaW9uIEdldC12Uk5JQVBJVmVyc2lvbiBHZXQtdlJOSUFwcGxpY2F0aW9uIEdldC12Uk5JQXBwbGljYXRpb25UaWVyIEdldC12Uk5JRGF0YVNvdXJjZSBHZXQtdlJOSURhdGFTb3VyY2VTTk1QQ29uZmlnIEdldC12Uk5JRGF0YXN0b3JlIEdldC12Uk5JRGlzdHJpYnV0ZWRTd2l0Y2ggR2V0LXZSTklEaXN0cmlidXRlZFN3aXRjaFBvcnRHcm91cCBHZXQtdlJOSUVudGl0eSBHZXQtdlJOSUVudGl0eU5hbWUgR2V0LXZSTklGaXJld2FsbFJ1bGUgR2V0LXZSTklGbG93IEdldC12Uk5JSG9zdCBHZXQtdlJOSUhvc3RWTUtOaWMgR2V0LXZSTklJUFNldCBHZXQtdlJOSUwyTmV0d29yayBHZXQtdlJOSU5TWE1hbmFnZXIgR2V0LXZSTklOb2RlcyBHZXQtdlJOSVByb2JsZW0gR2V0LXZSTklSZWNvbW1lbmRlZFJ1bGVzIEdldC12Uk5JUmVjb21tZW5kZWRSdWxlc05zeEJ1bmRsZSBHZXQtdlJOSVNlY3VyaXR5R3JvdXAgR2V0LXZSTklTZWN1cml0eVRhZyBHZXQtdlJOSVNlcnZpY2UgR2V0LXZSTklTZXJ2aWNlR3JvdXAgR2V0LXZSTklWTSBHZXQtdlJOSVZNdk5JQyBHZXQtdlJOSXZDZW50ZXIgR2V0LXZSTkl2Q2VudGVyQ2x1c3RlciBHZXQtdlJOSXZDZW50ZXJEYXRhY2VudGVyIEdldC12Uk5JdkNlbnRlckZvbGRlciBHcmFudC1Oc3hTcG9vZmd1YXJkTmljQXBwcm92YWwgSW1wb3J0LUNJVkFwcCBJbXBvcnQtQ0lWQXBwVGVtcGxhdGUgSW1wb3J0LU5zeE9iamVjdCBJbXBvcnQtUGFja2FnZVByb3ZpZGVyIEltcG9ydC1Qb3dlclNoZWxsRGF0YUZpbGUgSW1wb3J0LVNwYm1TdG9yYWdlUG9saWN5IEltcG9ydC1WQXBwIEltcG9ydC1WTUhvc3RQcm9maWxlIEltcG9ydC12UkFDb250ZW50RGF0YSBJbXBvcnQtdlJBSWNvbiBJbXBvcnQtdlJBUGFja2FnZSBJbml0aWFsaXplLUNvbmZpZ3VyYXRpb25SdW50aW1lU3RhdGUgSW5zdGFsbC1Nb2R1bGUgSW5zdGFsbC1Oc3hDbHVzdGVyIEluc3RhbGwtUGFja2FnZSBJbnN0YWxsLVBhY2thZ2VQcm92aWRlciBJbnN0YWxsLVNjcmlwdCBJbnN0YWxsLVZNSG9zdFBhdGNoIEludm9rZS1EcnNSZWNvbW1lbmRhdGlvbiBJbnZva2UtTnN4Q2xpIEludm9rZS1Oc3hDbHVzdGVyUmVzb2x2ZUFsbCBJbnZva2UtTnN4TWFuYWdlclN5bmMgSW52b2tlLU5zeFJlc3RNZXRob2QgSW52b2tlLU5zeFdlYlJlcXVlc3QgSW52b2tlLVZNSG9zdFByb2ZpbGUgSW52b2tlLVZNU2NyaXB0IEludm9rZS1YcGF0aFF1ZXJ5IEludm9rZS12UkFEYXRhQ29sbGVjdGlvbiBJbnZva2UtdlJBUmVzdE1ldGhvZCBJbnZva2UtdlJBVGVuYW50RGlyZWN0b3J5U3luYyBJbnZva2UtdlJOSVJlc3RNZXRob2QgSm9pbi1TdHJpbmcgTW91bnQtVG9vbHMgTW92ZS1DbHVzdGVyIE1vdmUtRGF0YWNlbnRlciBNb3ZlLURhdGFzdG9yZSBNb3ZlLUZvbGRlciBNb3ZlLUhhcmREaXNrIE1vdmUtSW52ZW50b3J5IE1vdmUtTnN4U2VjdXJpdHlQb2xpY3lSdWxlIE1vdmUtUmVzb3VyY2VQb29sIE1vdmUtVGVtcGxhdGUgTW92ZS1WQXBwIE1vdmUtVkRpc2sgTW92ZS1WTSBNb3ZlLVZNSG9zdCBOZXctQWR2YW5jZWRTZXR0aW5nIE5ldy1BbGFybUFjdGlvbiBOZXctQWxhcm1BY3Rpb25UcmlnZ2VyIE5ldy1DRERyaXZlIE5ldy1DSUFjY2Vzc0NvbnRyb2xSdWxlIE5ldy1DSVZBcHAgTmV3LUNJVkFwcE5ldHdvcmsgTmV3LUNJVkFwcFRlbXBsYXRlIE5ldy1DSVZNIE5ldy1DbHVzdGVyIE5ldy1DdXN0b21BdHRyaWJ1dGUgTmV3LURhdGFjZW50ZXIgTmV3LURhdGFzdG9yZSBOZXctRGF0YXN0b3JlQ2x1c3RlciBOZXctRGF0YXN0b3JlRHJpdmUgTmV3LURyc0NsdXN0ZXJHcm91cCBOZXctRHJzUnVsZSBOZXctRHJzVk1Ib3N0UnVsZSBOZXctRHNjQ2hlY2tzdW0gTmV3LUZsb3BweURyaXZlIE5ldy1Gb2xkZXIgTmV3LUd1aWQgTmV3LUhDWEFwcGxpYW5jZSBOZXctSENYTWlncmF0aW9uIE5ldy1IQ1hOZXR3b3JrRXh0ZW5zaW9uIE5ldy1IQ1hOZXR3b3JrTWFwcGluZyBOZXctSENYUmVwbGljYXRpb24gTmV3LUhDWFNpdGVQYWlyaW5nIE5ldy1IQ1hTdGF0aWNSb3V0ZSBOZXctSGFyZERpc2sgTmV3LUlTY3NpSGJhVGFyZ2V0IE5ldy1LbWlwQ2xpZW50Q2VydGlmaWNhdGUgTmV3LU5ldHdvcmtBZGFwdGVyIE5ldy1OZnNVc2VyIE5ldy1Oc3hBZGRyZXNzU3BlYyBOZXctTnN4Q2x1c3RlclZ4bGFuQ29uZmlnIE5ldy1Oc3hDb250cm9sbGVyIE5ldy1Oc3hEeW5hbWljQ3JpdGVyaWFTcGVjIE5ldy1Oc3hFZGdlIE5ldy1Oc3hFZGdlQmdwTmVpZ2hib3VyIE5ldy1Oc3hFZGdlQ3NyIE5ldy1Oc3hFZGdlRmlyZXdhbGxSdWxlIE5ldy1Oc3hFZGdlSW50ZXJmYWNlU3BlYyBOZXctTnN4RWRnZU5hdFJ1bGUgTmV3LU5zeEVkZ2VPc3BmQXJlYSBOZXctTnN4RWRnZU9zcGZJbnRlcmZhY2UgTmV3LU5zeEVkZ2VQcmVmaXggTmV3LU5zeEVkZ2VSZWRpc3RyaWJ1dGlvblJ1bGUgTmV3LU5zeEVkZ2VTZWxmU2lnbmVkQ2VydGlmaWNhdGUgTmV3LU5zeEVkZ2VTdGF0aWNSb3V0ZSBOZXctTnN4RWRnZVN1YkludGVyZmFjZSBOZXctTnN4RWRnZVN1YkludGVyZmFjZVNwZWMgTmV3LU5zeEZpcmV3YWxsUnVsZSBOZXctTnN4RmlyZXdhbGxTYXZlZENvbmZpZ3VyYXRpb24gTmV3LU5zeEZpcmV3YWxsU2VjdGlvbiBOZXctTnN4SXBQb29sIE5ldy1Oc3hJcFNldCBOZXctTnN4TG9hZEJhbGFuY2VyQXBwbGljYXRpb25Qcm9maWxlIE5ldy1Oc3hMb2FkQmFsYW5jZXJBcHBsaWNhdGlvblJ1bGUgTmV3LU5zeExvYWRCYWxhbmNlck1lbWJlclNwZWMgTmV3LU5zeExvYWRCYWxhbmNlck1vbml0b3IgTmV3LU5zeExvYWRCYWxhbmNlclBvb2wgTmV3LU5zeExvZ2ljYWxSb3V0ZXIgTmV3LU5zeExvZ2ljYWxSb3V0ZXJCZ3BOZWlnaGJvdXIgTmV3LU5zeExvZ2ljYWxSb3V0ZXJCcmlkZ2UgTmV3LU5zeExvZ2ljYWxSb3V0ZXJJbnRlcmZhY2UgTmV3LU5zeExvZ2ljYWxSb3V0ZXJJbnRlcmZhY2VTcGVjIE5ldy1Oc3hMb2dpY2FsUm91dGVyT3NwZkFyZWEgTmV3LU5zeExvZ2ljYWxSb3V0ZXJPc3BmSW50ZXJmYWNlIE5ldy1Oc3hMb2dpY2FsUm91dGVyUHJlZml4IE5ldy1Oc3hMb2dpY2FsUm91dGVyUmVkaXN0cmlidXRpb25SdWxlIE5ldy1Oc3hMb2dpY2FsUm91dGVyU3RhdGljUm91dGUgTmV3LU5zeExvZ2ljYWxTd2l0Y2ggTmV3LU5zeE1hY1NldCBOZXctTnN4TWFuYWdlciBOZXctTnN4U2VjdXJpdHlHcm91cCBOZXctTnN4U2VjdXJpdHlQb2xpY3kgTmV3LU5zeFNlY3VyaXR5UG9saWN5QXNzaWdubWVudCBOZXctTnN4U2VjdXJpdHlQb2xpY3lGaXJld2FsbFJ1bGVTcGVjIE5ldy1Oc3hTZWN1cml0eVBvbGljeUd1ZXN0SW50cm9zcGVjdGlvblNwZWMgTmV3LU5zeFNlY3VyaXR5UG9saWN5TmV0d29ya0ludHJvc3BlY3Rpb25TcGVjIE5ldy1Oc3hTZWN1cml0eVRhZyBOZXctTnN4U2VjdXJpdHlUYWdBc3NpZ25tZW50IE5ldy1Oc3hTZWdtZW50SWRSYW5nZSBOZXctTnN4U2VydmljZSBOZXctTnN4U2VydmljZUdyb3VwIE5ldy1Oc3hTcG9vZmd1YXJkUG9saWN5IE5ldy1Oc3hTc2xWcG5BdXRoU2VydmVyIE5ldy1Oc3hTc2xWcG5DbGllbnRJbnN0YWxsYXRpb25QYWNrYWdlIE5ldy1Oc3hTc2xWcG5JcFBvb2wgTmV3LU5zeFNzbFZwblByaXZhdGVOZXR3b3JrIE5ldy1Oc3hTc2xWcG5Vc2VyIE5ldy1Oc3hUcmFuc3BvcnRab25lIE5ldy1Oc3hWZHNDb250ZXh0IE5ldy1PU0N1c3RvbWl6YXRpb25OaWNNYXBwaW5nIE5ldy1PU0N1c3RvbWl6YXRpb25TcGVjIE5ldy1PcmcgTmV3LU9yZ05ldHdvcmsgTmV3LU9yZ1ZkYyBOZXctT3JnVmRjTmV0d29yayBOZXctUmVzb3VyY2VQb29sIE5ldy1TY3JpcHRGaWxlSW5mbyBOZXctU2NzaUNvbnRyb2xsZXIgTmV3LVNuYXBzaG90IE5ldy1TcGJtUnVsZSBOZXctU3BibVJ1bGVTZXQgTmV3LVNwYm1TdG9yYWdlUG9saWN5IE5ldy1TdGF0SW50ZXJ2YWwgTmV3LVRhZyBOZXctVGFnQXNzaWdubWVudCBOZXctVGFnQ2F0ZWdvcnkgTmV3LVRlbXBsYXRlIE5ldy1UZW1wb3JhcnlGaWxlIE5ldy1WQUlPRmlsdGVyIE5ldy1WQXBwIE5ldy1WRFBvcnRncm91cCBOZXctVkRTd2l0Y2ggTmV3LVZEU3dpdGNoUHJpdmF0ZVZsYW4gTmV3LVZEaXNrIE5ldy1WSUNyZWRlbnRpYWxTdG9yZUl0ZW0gTmV3LVZJSW52ZW50b3J5RHJpdmUgTmV3LVZJUGVybWlzc2lvbiBOZXctVklQcm9wZXJ0eSBOZXctVklSb2xlIE5ldy1WSVNhbWxTZWN1cml0eUNvbnRleHQgTmV3LVZNIE5ldy1WTUhvc3RBY2NvdW50IE5ldy1WTUhvc3ROZXR3b3JrQWRhcHRlciBOZXctVk1Ib3N0UHJvZmlsZSBOZXctVk1Ib3N0UHJvZmlsZVZtUG9ydEdyb3VwQ29uZmlndXJhdGlvbiBOZXctVk1Ib3N0Um91dGUgTmV3LVZUcG0gTmV3LVZhc2FQcm92aWRlciBOZXctVmNzT0F1dGhTZWN1cml0eUNvbnRleHQgTmV3LVZpcnR1YWxQb3J0R3JvdXAgTmV3LVZpcnR1YWxTd2l0Y2ggTmV3LVZzYW5EaXNrIE5ldy1Wc2FuRGlza0dyb3VwIE5ldy1Wc2FuRmF1bHREb21haW4gTmV3LVZzYW5Jc2NzaUluaXRpYXRvckdyb3VwIE5ldy1Wc2FuSXNjc2lJbml0aWF0b3JHcm91cFRhcmdldEFzc29jaWF0aW9uIE5ldy1Wc2FuSXNjc2lMdW4gTmV3LVZzYW5Jc2NzaVRhcmdldCBOZXctdlJBQnVzaW5lc3NHcm91cCBOZXctdlJBRW50aXRsZW1lbnQgTmV3LXZSQUV4dGVybmFsTmV0d29ya1Byb2ZpbGUgTmV3LXZSQUdyb3VwUHJpbmNpcGFsIE5ldy12UkFOQVROZXR3b3JrUHJvZmlsZSBOZXctdlJBTmV0d29ya1Byb2ZpbGVJUFJhbmdlRGVmaW5pdGlvbiBOZXctdlJBUGFja2FnZSBOZXctdlJBUHJvcGVydHlEZWZpbml0aW9uIE5ldy12UkFQcm9wZXJ0eUdyb3VwIE5ldy12UkFSZXNlcnZhdGlvbiBOZXctdlJBUmVzZXJ2YXRpb25OZXR3b3JrRGVmaW5pdGlvbiBOZXctdlJBUmVzZXJ2YXRpb25Qb2xpY3kgTmV3LXZSQVJlc2VydmF0aW9uU3RvcmFnZURlZmluaXRpb24gTmV3LXZSQVJvdXRlZE5ldHdvcmtQcm9maWxlIE5ldy12UkFTZXJ2aWNlIE5ldy12UkFTdG9yYWdlUmVzZXJ2YXRpb25Qb2xpY3kgTmV3LXZSQVRlbmFudCBOZXctdlJBVGVuYW50RGlyZWN0b3J5IE5ldy12UkFVc2VyUHJpbmNpcGFsIE5ldy12Uk5JQXBwbGljYXRpb24gTmV3LXZSTklBcHBsaWNhdGlvblRpZXIgTmV3LXZSTklEYXRhU291cmNlIE9wZW4tVk1Db25zb2xlV2luZG93IFB1Ymxpc2gtTW9kdWxlIFB1Ymxpc2gtTnN4U3Bvb2ZndWFyZFBvbGljeSBQdWJsaXNoLVNjcmlwdCBSZWdpc3Rlci1QU1JlcG9zaXRvcnkgUmVnaXN0ZXItUGFja2FnZVNvdXJjZSBSZW1vdmUtQWR2YW5jZWRTZXR0aW5nIFJlbW92ZS1BbGFybUFjdGlvbiBSZW1vdmUtQWxhcm1BY3Rpb25UcmlnZ2VyIFJlbW92ZS1BbGlhcyBSZW1vdmUtQ0REcml2ZSBSZW1vdmUtQ0lBY2Nlc3NDb250cm9sUnVsZSBSZW1vdmUtQ0lWQXBwIFJlbW92ZS1DSVZBcHBOZXR3b3JrIFJlbW92ZS1DSVZBcHBUZW1wbGF0ZSBSZW1vdmUtQ2x1c3RlciBSZW1vdmUtQ3VzdG9tQXR0cmlidXRlIFJlbW92ZS1EYXRhY2VudGVyIFJlbW92ZS1EYXRhc3RvcmUgUmVtb3ZlLURhdGFzdG9yZUNsdXN0ZXIgUmVtb3ZlLURyc0NsdXN0ZXJHcm91cCBSZW1vdmUtRHJzUnVsZSBSZW1vdmUtRHJzVk1Ib3N0UnVsZSBSZW1vdmUtRmxvcHB5RHJpdmUgUmVtb3ZlLUZvbGRlciBSZW1vdmUtSENYQXBwbGlhbmNlIFJlbW92ZS1IQ1hOZXR3b3JrRXh0ZW5zaW9uIFJlbW92ZS1IQ1hSZXBsaWNhdGlvbiBSZW1vdmUtSENYU2l0ZVBhaXJpbmcgUmVtb3ZlLUhhcmREaXNrIFJlbW92ZS1JU2NzaUhiYVRhcmdldCBSZW1vdmUtSW52ZW50b3J5IFJlbW92ZS1LZXlNYW5hZ2VtZW50U2VydmVyIFJlbW92ZS1OZXR3b3JrQWRhcHRlciBSZW1vdmUtTmZzVXNlciBSZW1vdmUtTnN4Q2x1c3RlciBSZW1vdmUtTnN4Q2x1c3RlclZ4bGFuQ29uZmlnIFJlbW92ZS1Oc3hDb250cm9sbGVyIFJlbW92ZS1Oc3hEeW5hbWljQ3JpdGVyaWEgUmVtb3ZlLU5zeER5bmFtaWNNZW1iZXJTZXQgUmVtb3ZlLU5zeEVkZ2UgUmVtb3ZlLU5zeEVkZ2VCZ3BOZWlnaGJvdXIgUmVtb3ZlLU5zeEVkZ2VDZXJ0aWZpY2F0ZSBSZW1vdmUtTnN4RWRnZUNzciBSZW1vdmUtTnN4RWRnZUZpcmV3YWxsUnVsZSBSZW1vdmUtTnN4RWRnZUludGVyZmFjZUFkZHJlc3MgUmVtb3ZlLU5zeEVkZ2VOYXRSdWxlIFJlbW92ZS1Oc3hFZGdlT3NwZkFyZWEgUmVtb3ZlLU5zeEVkZ2VPc3BmSW50ZXJmYWNlIFJlbW92ZS1Oc3hFZGdlUHJlZml4IFJlbW92ZS1Oc3hFZGdlUmVkaXN0cmlidXRpb25SdWxlIFJlbW92ZS1Oc3hFZGdlU3RhdGljUm91dGUgUmVtb3ZlLU5zeEVkZ2VTdWJJbnRlcmZhY2UgUmVtb3ZlLU5zeEZpcmV3YWxsRXhjbHVzaW9uTGlzdE1lbWJlciBSZW1vdmUtTnN4RmlyZXdhbGxSdWxlIFJlbW92ZS1Oc3hGaXJld2FsbFJ1bGVNZW1iZXIgUmVtb3ZlLU5zeEZpcmV3YWxsU2F2ZWRDb25maWd1cmF0aW9uIFJlbW92ZS1Oc3hGaXJld2FsbFNlY3Rpb24gUmVtb3ZlLU5zeElwUG9vbCBSZW1vdmUtTnN4SXBTZXQgUmVtb3ZlLU5zeElwU2V0TWVtYmVyIFJlbW92ZS1Oc3hMb2FkQmFsYW5jZXJBcHBsaWNhdGlvblByb2ZpbGUgUmVtb3ZlLU5zeExvYWRCYWxhbmNlck1vbml0b3IgUmVtb3ZlLU5zeExvYWRCYWxhbmNlclBvb2wgUmVtb3ZlLU5zeExvYWRCYWxhbmNlclBvb2xNZW1iZXIgUmVtb3ZlLU5zeExvYWRCYWxhbmNlclZpcCBSZW1vdmUtTnN4TG9naWNhbFJvdXRlciBSZW1vdmUtTnN4TG9naWNhbFJvdXRlckJncE5laWdoYm91ciBSZW1vdmUtTnN4TG9naWNhbFJvdXRlckJyaWRnZSBSZW1vdmUtTnN4TG9naWNhbFJvdXRlckludGVyZmFjZSBSZW1vdmUtTnN4TG9naWNhbFJvdXRlck9zcGZBcmVhIFJlbW92ZS1Oc3hMb2dpY2FsUm91dGVyT3NwZkludGVyZmFjZSBSZW1vdmUtTnN4TG9naWNhbFJvdXRlclByZWZpeCBSZW1vdmUtTnN4TG9naWNhbFJvdXRlclJlZGlzdHJpYnV0aW9uUnVsZSBSZW1vdmUtTnN4TG9naWNhbFJvdXRlclN0YXRpY1JvdXRlIFJlbW92ZS1Oc3hMb2dpY2FsU3dpdGNoIFJlbW92ZS1Oc3hNYWNTZXQgUmVtb3ZlLU5zeFNlY29uZGFyeU1hbmFnZXIgUmVtb3ZlLU5zeFNlY3VyaXR5R3JvdXAgUmVtb3ZlLU5zeFNlY3VyaXR5R3JvdXBNZW1iZXIgUmVtb3ZlLU5zeFNlY3VyaXR5UG9saWN5IFJlbW92ZS1Oc3hTZWN1cml0eVBvbGljeUFzc2lnbm1lbnQgUmVtb3ZlLU5zeFNlY3VyaXR5UG9saWN5UnVsZSBSZW1vdmUtTnN4U2VjdXJpdHlQb2xpY3lSdWxlR3JvdXAgUmVtb3ZlLU5zeFNlY3VyaXR5UG9saWN5UnVsZVNlcnZpY2UgUmVtb3ZlLU5zeFNlY3VyaXR5VGFnIFJlbW92ZS1Oc3hTZWN1cml0eVRhZ0Fzc2lnbm1lbnQgUmVtb3ZlLU5zeFNlZ21lbnRJZFJhbmdlIFJlbW92ZS1Oc3hTZXJ2aWNlIFJlbW92ZS1Oc3hTZXJ2aWNlR3JvdXAgUmVtb3ZlLU5zeFNwb29mZ3VhcmRQb2xpY3kgUmVtb3ZlLU5zeFNzbFZwbkNsaWVudEluc3RhbGxhdGlvblBhY2thZ2UgUmVtb3ZlLU5zeFNzbFZwbklwUG9vbCBSZW1vdmUtTnN4U3NsVnBuUHJpdmF0ZU5ldHdvcmsgUmVtb3ZlLU5zeFNzbFZwblVzZXIgUmVtb3ZlLU5zeFRyYW5zcG9ydFpvbmUgUmVtb3ZlLU5zeFRyYW5zcG9ydFpvbmVNZW1iZXIgUmVtb3ZlLU5zeFZkc0NvbnRleHQgUmVtb3ZlLU9TQ3VzdG9taXphdGlvbk5pY01hcHBpbmcgUmVtb3ZlLU9TQ3VzdG9taXphdGlvblNwZWMgUmVtb3ZlLU9yZyBSZW1vdmUtT3JnTmV0d29yayBSZW1vdmUtT3JnVmRjIFJlbW92ZS1PcmdWZGNOZXR3b3JrIFJlbW92ZS1QU1JlYWRMaW5lS2V5SGFuZGxlciBSZW1vdmUtUGFzc3Rocm91Z2hEZXZpY2UgUmVtb3ZlLVJlc291cmNlUG9vbCBSZW1vdmUtU25hcHNob3QgUmVtb3ZlLVNwYm1TdG9yYWdlUG9saWN5IFJlbW92ZS1TdGF0SW50ZXJ2YWwgUmVtb3ZlLVRhZyBSZW1vdmUtVGFnQXNzaWdubWVudCBSZW1vdmUtVGFnQ2F0ZWdvcnkgUmVtb3ZlLVRlbXBsYXRlIFJlbW92ZS1Vc2JEZXZpY2UgUmVtb3ZlLVZBSU9GaWx0ZXIgUmVtb3ZlLVZBcHAgUmVtb3ZlLVZEUG9ydEdyb3VwIFJlbW92ZS1WRFN3aXRjaCBSZW1vdmUtVkRTd2l0Y2hQaHlzaWNhbE5ldHdvcmtBZGFwdGVyIFJlbW92ZS1WRFN3aXRjaFByaXZhdGVWbGFuIFJlbW92ZS1WRFN3aXRjaFZNSG9zdCBSZW1vdmUtVkRpc2sgUmVtb3ZlLVZJQ3JlZGVudGlhbFN0b3JlSXRlbSBSZW1vdmUtVklQZXJtaXNzaW9uIFJlbW92ZS1WSVByb3BlcnR5IFJlbW92ZS1WSVJvbGUgUmVtb3ZlLVZNIFJlbW92ZS1WTUhvc3QgUmVtb3ZlLVZNSG9zdEFjY291bnQgUmVtb3ZlLVZNSG9zdE5ldHdvcmtBZGFwdGVyIFJlbW92ZS1WTUhvc3ROdHBTZXJ2ZXIgUmVtb3ZlLVZNSG9zdFByb2ZpbGUgUmVtb3ZlLVZNSG9zdFByb2ZpbGVWbVBvcnRHcm91cENvbmZpZ3VyYXRpb24gUmVtb3ZlLVZNSG9zdFJvdXRlIFJlbW92ZS1WVHBtIFJlbW92ZS1WYXNhUHJvdmlkZXIgUmVtb3ZlLVZpcnR1YWxQb3J0R3JvdXAgUmVtb3ZlLVZpcnR1YWxTd2l0Y2ggUmVtb3ZlLVZpcnR1YWxTd2l0Y2hQaHlzaWNhbE5ldHdvcmtBZGFwdGVyIFJlbW92ZS1Wc2FuRGlzayBSZW1vdmUtVnNhbkRpc2tHcm91cCBSZW1vdmUtVnNhbkZhdWx0RG9tYWluIFJlbW92ZS1Wc2FuSXNjc2lJbml0aWF0b3JHcm91cCBSZW1vdmUtVnNhbklzY3NpSW5pdGlhdG9yR3JvdXBUYXJnZXRBc3NvY2lhdGlvbiBSZW1vdmUtVnNhbklzY3NpTHVuIFJlbW92ZS1Wc2FuSXNjc2lUYXJnZXQgUmVtb3ZlLXZSQUJ1c2luZXNzR3JvdXAgUmVtb3ZlLXZSQUN1c3RvbUZvcm0gUmVtb3ZlLXZSQUV4dGVybmFsTmV0d29ya1Byb2ZpbGUgUmVtb3ZlLXZSQUdyb3VwUHJpbmNpcGFsIFJlbW92ZS12UkFJY29uIFJlbW92ZS12UkFOQVROZXR3b3JrUHJvZmlsZSBSZW1vdmUtdlJBUGFja2FnZSBSZW1vdmUtdlJBUHJpbmNpcGFsRnJvbVRlbmFudFJvbGUgUmVtb3ZlLXZSQVByb3BlcnR5RGVmaW5pdGlvbiBSZW1vdmUtdlJBUHJvcGVydHlHcm91cCBSZW1vdmUtdlJBUmVzZXJ2YXRpb24gUmVtb3ZlLXZSQVJlc2VydmF0aW9uTmV0d29yayBSZW1vdmUtdlJBUmVzZXJ2YXRpb25Qb2xpY3kgUmVtb3ZlLXZSQVJlc2VydmF0aW9uU3RvcmFnZSBSZW1vdmUtdlJBUm91dGVkTmV0d29ya1Byb2ZpbGUgUmVtb3ZlLXZSQVNlcnZpY2UgUmVtb3ZlLXZSQVN0b3JhZ2VSZXNlcnZhdGlvblBvbGljeSBSZW1vdmUtdlJBVGVuYW50IFJlbW92ZS12UkFUZW5hbnREaXJlY3RvcnkgUmVtb3ZlLXZSQVVzZXJQcmluY2lwYWwgUmVtb3ZlLXZSTklBcHBsaWNhdGlvbiBSZW1vdmUtdlJOSUFwcGxpY2F0aW9uVGllciBSZW1vdmUtdlJOSURhdGFTb3VyY2UgUmVwYWlyLU5zeEVkZ2UgUmVwYWlyLVZzYW5PYmplY3QgUmVxdWVzdC12UkFDYXRhbG9nSXRlbSBSZXF1ZXN0LXZSQVJlc291cmNlQWN0aW9uIFJlc3RhcnQtQ0lWQXBwIFJlc3RhcnQtQ0lWQXBwR3Vlc3QgUmVzdGFydC1DSVZNIFJlc3RhcnQtQ0lWTUd1ZXN0IFJlc3RhcnQtVk0gUmVzdGFydC1WTUd1ZXN0IFJlc3RhcnQtVk1Ib3N0IFJlc3RhcnQtVk1Ib3N0U2VydmljZSBSZXN1bWUtSENYUmVwbGljYXRpb24gUmV2b2tlLU5zeFNwb29mZ3VhcmROaWNBcHByb3ZhbCBTYXZlLU1vZHVsZSBTYXZlLVBhY2thZ2UgU2F2ZS1TY3JpcHQgU2VhcmNoLUNsb3VkIFNldC1BZHZhbmNlZFNldHRpbmcgU2V0LUFsYXJtRGVmaW5pdGlvbiBTZXQtQW5ub3RhdGlvbiBTZXQtQ0REcml2ZSBTZXQtQ0lBY2Nlc3NDb250cm9sUnVsZSBTZXQtQ0lOZXR3b3JrQWRhcHRlciBTZXQtQ0lWQXBwIFNldC1DSVZBcHBOZXR3b3JrIFNldC1DSVZBcHBTdGFydFJ1bGUgU2V0LUNJVkFwcFRlbXBsYXRlIFNldC1DbHVzdGVyIFNldC1DdXN0b21BdHRyaWJ1dGUgU2V0LURhdGFjZW50ZXIgU2V0LURhdGFzdG9yZSBTZXQtRGF0YXN0b3JlQ2x1c3RlciBTZXQtRHJzQ2x1c3Rlckdyb3VwIFNldC1EcnNSdWxlIFNldC1EcnNWTUhvc3RSdWxlIFNldC1GbG9wcHlEcml2ZSBTZXQtRm9sZGVyIFNldC1IQ1hBcHBsaWFuY2UgU2V0LUhDWE1pZ3JhdGlvbiBTZXQtSENYUmVwbGljYXRpb24gU2V0LUhhcmREaXNrIFNldC1JU2NzaUhiYVRhcmdldCBTZXQtS2V5TWFuYWdlbWVudFNlcnZlciBTZXQtS21zQ2x1c3RlciBTZXQtTWFya2Rvd25PcHRpb24gU2V0LU5ldHdvcmtBZGFwdGVyIFNldC1OZnNVc2VyIFNldC1OaWNUZWFtaW5nUG9saWN5IFNldC1Ob2RlRXhjbHVzaXZlUmVzb3VyY2VzIFNldC1Ob2RlTWFuYWdlciBTZXQtTm9kZVJlc291cmNlU291cmNlIFNldC1Ob2RlUmVzb3VyY2VzIFNldC1Oc3hFZGdlIFNldC1Oc3hFZGdlQmdwIFNldC1Oc3hFZGdlRmlyZXdhbGwgU2V0LU5zeEVkZ2VJbnRlcmZhY2UgU2V0LU5zeEVkZ2VOYXQgU2V0LU5zeEVkZ2VPc3BmIFNldC1Oc3hFZGdlUm91dGluZyBTZXQtTnN4RmlyZXdhbGxHbG9iYWxDb25maWd1cmF0aW9uIFNldC1Oc3hGaXJld2FsbFJ1bGUgU2V0LU5zeEZpcmV3YWxsU2F2ZWRDb25maWd1cmF0aW9uIFNldC1Oc3hGaXJld2FsbFRocmVzaG9sZCBTZXQtTnN4TG9hZEJhbGFuY2VyIFNldC1Oc3hMb2FkQmFsYW5jZXJQb29sTWVtYmVyIFNldC1Oc3hMb2dpY2FsUm91dGVyIFNldC1Oc3hMb2dpY2FsUm91dGVyQmdwIFNldC1Oc3hMb2dpY2FsUm91dGVyQnJpZGdpbmcgU2V0LU5zeExvZ2ljYWxSb3V0ZXJJbnRlcmZhY2UgU2V0LU5zeExvZ2ljYWxSb3V0ZXJPc3BmIFNldC1Oc3hMb2dpY2FsUm91dGVyUm91dGluZyBTZXQtTnN4TWFuYWdlciBTZXQtTnN4TWFuYWdlclJvbGUgU2V0LU5zeE1hbmFnZXJUaW1lU2V0dGluZ3MgU2V0LU5zeFNlY3VyaXR5UG9saWN5IFNldC1Oc3hTZWN1cml0eVBvbGljeUZpcmV3YWxsUnVsZSBTZXQtTnN4U3NsVnBuIFNldC1PU0N1c3RvbWl6YXRpb25OaWNNYXBwaW5nIFNldC1PU0N1c3RvbWl6YXRpb25TcGVjIFNldC1PcmcgU2V0LU9yZ05ldHdvcmsgU2V0LU9yZ1ZkYyBTZXQtT3JnVmRjTmV0d29yayBTZXQtUFNDdXJyZW50Q29uZmlndXJhdGlvbk5vZGUgU2V0LVBTRGVmYXVsdENvbmZpZ3VyYXRpb25Eb2N1bWVudCBTZXQtUFNNZXRhQ29uZmlnRG9jSW5zUHJvY2Vzc2VkQmVmb3JlTWV0YSBTZXQtUFNNZXRhQ29uZmlnVmVyc2lvbkluZm9WMiBTZXQtUFNSZWFkTGluZUtleUhhbmRsZXIgU2V0LVBTUmVhZExpbmVPcHRpb24gU2V0LVBTUmVwb3NpdG9yeSBTZXQtUFNUb3BDb25maWd1cmF0aW9uTmFtZSBTZXQtUGFja2FnZVNvdXJjZSBTZXQtUG93ZXJDTElDb25maWd1cmF0aW9uIFNldC1SZXNvdXJjZVBvb2wgU2V0LVNjc2lDb250cm9sbGVyIFNldC1TY3NpTHVuIFNldC1TY3NpTHVuUGF0aCBTZXQtU2VjdXJpdHlQb2xpY3kgU2V0LVNuYXBzaG90IFNldC1TcGJtRW50aXR5Q29uZmlndXJhdGlvbiBTZXQtU3BibVN0b3JhZ2VQb2xpY3kgU2V0LVN0YXRJbnRlcnZhbCBTZXQtVGFnIFNldC1UYWdDYXRlZ29yeSBTZXQtVGVtcGxhdGUgU2V0LVZBSU9GaWx0ZXIgU2V0LVZBcHAgU2V0LVZEQmxvY2tlZFBvbGljeSBTZXQtVkRQb3J0IFNldC1WRFBvcnRncm91cCBTZXQtVkRQb3J0Z3JvdXBPdmVycmlkZVBvbGljeSBTZXQtVkRTZWN1cml0eVBvbGljeSBTZXQtVkRTd2l0Y2ggU2V0LVZEVHJhZmZpY1NoYXBpbmdQb2xpY3kgU2V0LVZEVXBsaW5rTGFjcFBvbGljeSBTZXQtVkRVcGxpbmtUZWFtaW5nUG9saWN5IFNldC1WRFZsYW5Db25maWd1cmF0aW9uIFNldC1WRGlzayBTZXQtVklQZXJtaXNzaW9uIFNldC1WSVJvbGUgU2V0LVZNIFNldC1WTUhvc3QgU2V0LVZNSG9zdEFjY291bnQgU2V0LVZNSG9zdEFkdmFuY2VkQ29uZmlndXJhdGlvbiBTZXQtVk1Ib3N0QXV0aGVudGljYXRpb24gU2V0LVZNSG9zdERpYWdub3N0aWNQYXJ0aXRpb24gU2V0LVZNSG9zdEZpcmV3YWxsRGVmYXVsdFBvbGljeSBTZXQtVk1Ib3N0RmlyZXdhbGxFeGNlcHRpb24gU2V0LVZNSG9zdEZpcm13YXJlIFNldC1WTUhvc3RIYmEgU2V0LVZNSG9zdE1vZHVsZSBTZXQtVk1Ib3N0TmV0d29yayBTZXQtVk1Ib3N0TmV0d29ya0FkYXB0ZXIgU2V0LVZNSG9zdFByb2ZpbGUgU2V0LVZNSG9zdFByb2ZpbGVJbWFnZUNhY2hlQ29uZmlndXJhdGlvbiBTZXQtVk1Ib3N0UHJvZmlsZVN0b3JhZ2VEZXZpY2VDb25maWd1cmF0aW9uIFNldC1WTUhvc3RQcm9maWxlVXNlckNvbmZpZ3VyYXRpb24gU2V0LVZNSG9zdFByb2ZpbGVWbVBvcnRHcm91cENvbmZpZ3VyYXRpb24gU2V0LVZNSG9zdFJvdXRlIFNldC1WTUhvc3RTZXJ2aWNlIFNldC1WTUhvc3RTbm1wIFNldC1WTUhvc3RTdGFydFBvbGljeSBTZXQtVk1Ib3N0U3RvcmFnZSBTZXQtVk1Ib3N0U3lzTG9nU2VydmVyIFNldC1WTVF1ZXN0aW9uIFNldC1WTVJlc291cmNlQ29uZmlndXJhdGlvbiBTZXQtVk1TdGFydFBvbGljeSBTZXQtVlRwbSBTZXQtVmlydHVhbFBvcnRHcm91cCBTZXQtVmlydHVhbFN3aXRjaCBTZXQtVnNhbkNsdXN0ZXJDb25maWd1cmF0aW9uIFNldC1Wc2FuRmF1bHREb21haW4gU2V0LVZzYW5Jc2NzaUluaXRpYXRvckdyb3VwIFNldC1Wc2FuSXNjc2lMdW4gU2V0LVZzYW5Jc2NzaVRhcmdldCBTZXQtdlJBQnVzaW5lc3NHcm91cCBTZXQtdlJBQ2F0YWxvZ0l0ZW0gU2V0LXZSQUN1c3RvbUZvcm0gU2V0LXZSQUVudGl0bGVtZW50IFNldC12UkFFeHRlcm5hbE5ldHdvcmtQcm9maWxlIFNldC12UkFOQVROZXR3b3JrUHJvZmlsZSBTZXQtdlJBUmVzZXJ2YXRpb24gU2V0LXZSQVJlc2VydmF0aW9uTmV0d29yayBTZXQtdlJBUmVzZXJ2YXRpb25Qb2xpY3kgU2V0LXZSQVJlc2VydmF0aW9uU3RvcmFnZSBTZXQtdlJBUm91dGVkTmV0d29ya1Byb2ZpbGUgU2V0LXZSQVNlcnZpY2UgU2V0LXZSQVN0b3JhZ2VSZXNlcnZhdGlvblBvbGljeSBTZXQtdlJBVGVuYW50IFNldC12UkFUZW5hbnREaXJlY3RvcnkgU2V0LXZSQVVzZXJQcmluY2lwYWwgU2V0LXZSTklEYXRhU291cmNlU05NUENvbmZpZyBTaG93LU1hcmtkb3duIFN0YXJ0LUNJVkFwcCBTdGFydC1DSVZNIFN0YXJ0LUhDWE1pZ3JhdGlvbiBTdGFydC1IQ1hSZXBsaWNhdGlvbiBTdGFydC1TcGJtUmVwbGljYXRpb25GYWlsb3ZlciBTdGFydC1TcGJtUmVwbGljYXRpb25QcmVwYXJlRmFpbG92ZXIgU3RhcnQtU3BibVJlcGxpY2F0aW9uUHJvbW90ZSBTdGFydC1TcGJtUmVwbGljYXRpb25SZXZlcnNlIFN0YXJ0LVNwYm1SZXBsaWNhdGlvblRlc3RGYWlsb3ZlciBTdGFydC1UaHJlYWRKb2IgU3RhcnQtVkFwcCBTdGFydC1WTSBTdGFydC1WTUhvc3QgU3RhcnQtVk1Ib3N0U2VydmljZSBTdGFydC1Wc2FuQ2x1c3RlckRpc2tVcGRhdGUgU3RhcnQtVnNhbkNsdXN0ZXJSZWJhbGFuY2UgU3RhcnQtVnNhbkVuY3J5cHRpb25Db25maWd1cmF0aW9uIFN0b3AtQ0lWQXBwIFN0b3AtQ0lWQXBwR3Vlc3QgU3RvcC1DSVZNIFN0b3AtQ0lWTUd1ZXN0IFN0b3AtU3BibVJlcGxpY2F0aW9uVGVzdEZhaWxvdmVyIFN0b3AtVGFzayBTdG9wLVZBcHAgU3RvcC1WTSBTdG9wLVZNR3Vlc3QgU3RvcC1WTUhvc3QgU3RvcC1WTUhvc3RTZXJ2aWNlIFN0b3AtVnNhbkNsdXN0ZXJSZWJhbGFuY2UgU3VzcGVuZC1DSVZBcHAgU3VzcGVuZC1DSVZNIFN1c3BlbmQtSENYUmVwbGljYXRpb24gU3VzcGVuZC1WTSBTdXNwZW5kLVZNR3Vlc3QgU3VzcGVuZC1WTUhvc3QgU3luYy1TcGJtUmVwbGljYXRpb25Hcm91cCBUZXN0LUNvbmZsaWN0aW5nUmVzb3VyY2VzIFRlc3QtSENYTWlncmF0aW9uIFRlc3QtSENYUmVwbGljYXRpb24gVGVzdC1Kc29uIFRlc3QtTW9kdWxlUmVsb2FkUmVxdWlyZWQgVGVzdC1Nb2ZJbnN0YW5jZVRleHQgVGVzdC1Ob2RlTWFuYWdlciBUZXN0LU5vZGVSZXNvdXJjZVNvdXJjZSBUZXN0LU5vZGVSZXNvdXJjZXMgVGVzdC1TY3JpcHRGaWxlSW5mbyBUZXN0LVZNSG9zdFByb2ZpbGVDb21wbGlhbmNlIFRlc3QtVk1Ib3N0U25tcCBUZXN0LVZzYW5DbHVzdGVySGVhbHRoIFRlc3QtVnNhbk5ldHdvcmtQZXJmb3JtYW5jZSBUZXN0LVZzYW5TdG9yYWdlUGVyZm9ybWFuY2UgVGVzdC1Wc2FuVk1DcmVhdGlvbiBUZXN0LXZSQVBhY2thZ2UgVW5pbnN0YWxsLU1vZHVsZSBVbmluc3RhbGwtUGFja2FnZSBVbmluc3RhbGwtU2NyaXB0IFVubG9jay1WTSBVbnJlZ2lzdGVyLVBTUmVwb3NpdG9yeSBVbnJlZ2lzdGVyLVBhY2thZ2VTb3VyY2UgVXBkYXRlLUNvbmZpZ3VyYXRpb25Eb2N1bWVudFJlZiBVcGRhdGUtQ29uZmlndXJhdGlvbkVycm9yQ291bnQgVXBkYXRlLURlcGVuZHNPbiBVcGRhdGUtTG9jYWxDb25maWdNYW5hZ2VyIFVwZGF0ZS1Nb2R1bGUgVXBkYXRlLU1vZHVsZU1hbmlmZXN0IFVwZGF0ZS1Nb2R1bGVWZXJzaW9uIFVwZGF0ZS1Qb3dlck5zeCBVcGRhdGUtU2NyaXB0IFVwZGF0ZS1TY3JpcHRGaWxlSW5mbyBVcGRhdGUtVG9vbHMgVXBkYXRlLVZzYW5IY2xEYXRhYmFzZSBWYWxpZGF0ZVVwZGF0ZS1Db25maWd1cmF0aW9uRGF0YSBXYWl0LURlYnVnZ2VyIFdhaXQtTnN4Q29udHJvbGxlckpvYiBXYWl0LU5zeEdlbmVyaWNKb2IgV2FpdC1Oc3hKb2IgV2FpdC1UYXNrIFdhaXQtVG9vbHMgV3JpdGUtSW5mb3JtYXRpb24gV3JpdGUtTG9nIFdyaXRlLU1ldGFDb25maWdGaWxlIFdyaXRlLU5vZGVNT0ZGaWxlIixub21hcmt1cDoiLW5lIC1lcSAtbHQgLWd0IC1nZSAtbGUgLW5vdCAtbGlrZSAtbm90bGlrZSAtbWF0Y2ggLW5vdG1hdGNoIC1jb250YWlucyAtbm90Y29udGFpbnMgLWluIC1ub3RpbiAtcmVwbGFjZSJ9LGM6W3QsZS5OTSxhLHtjTjoic3RyaW5nIix2Olt7YjovJy8sZTovJy99LHtiOi9AJy8sZTovXidAL31dfSx7Y046ImxpdGVyYWwiLGI6L1wkKG51bGx8dHJ1ZXxmYWxzZSlcYi99LHIsb119fSksby5yZWdpc3Rlckxhbmd1YWdlKCJweXRob24iLGZ1bmN0aW9uKGUpe3ZhciB0PXtrZXl3b3JkOiJhbmQgZWxpZiBpcyBnbG9iYWwgYXMgaW4gaWYgZnJvbSByYWlzZSBmb3IgZXhjZXB0IGZpbmFsbHkgcHJpbnQgaW1wb3J0IHBhc3MgcmV0dXJuIGV4ZWMgZWxzZSBicmVhayBub3Qgd2l0aCBjbGFzcyBhc3NlcnQgeWllbGQgdHJ5IHdoaWxlIGNvbnRpbnVlIGRlbCBvciBkZWYgbGFtYmRhIGFzeW5jIGF3YWl0IG5vbmxvY2FsfDEwIixidWlsdF9pbjoiRWxsaXBzaXMgTm90SW1wbGVtZW50ZWQiLGxpdGVyYWw6IkZhbHNlIE5vbmUgVHJ1ZSJ9LHI9e2NOOiJtZXRhIixiOi9eKD4+PnxcLlwuXC4pIC99LGE9e2NOOiJzdWJzdCIsYjovXHsvLGU6L1x9LyxrOnQsaTovIy99LG89e2NOOiJzdHJpbmciLGM6W2UuQkVdLHY6W3tiOi8odXxiKT9yPycnJy8sZTovJycnLyxjOltlLkJFLHJdLHI6MTB9LHtiOi8odXxiKT9yPyIiIi8sZTovIiIiLyxjOltlLkJFLHJdLHI6MTB9LHtiOi8oZnJ8cmZ8ZiknJycvLGU6LycnJy8sYzpbZS5CRSxyLGFdfSx7YjovKGZyfHJmfGYpIiIiLyxlOi8iIiIvLGM6W2UuQkUscixhXX0se2I6Lyh1fHJ8dXIpJy8sZTovJy8scjoxMH0se2I6Lyh1fHJ8dXIpIi8sZTovIi8scjoxMH0se2I6LyhifGJyKScvLGU6LycvfSx7YjovKGJ8YnIpIi8sZTovIi99LHtiOi8oZnJ8cmZ8ZiknLyxlOi8nLyxjOltlLkJFLGFdfSx7YjovKGZyfHJmfGYpIi8sZTovIi8sYzpbZS5CRSxhXX0sZS5BU00sZS5RU01dfSxpPXtjTjoibnVtYmVyIixyOjAsdjpbe2I6ZS5CTlIrIltsTGpKXT8ifSx7YjoiXFxiKDBvWzAtN10rKVtsTGpKXT8ifSx7YjplLkNOUisiW2xMakpdPyJ9XX0sbj17Y046InBhcmFtcyIsYjovXCgvLGU6L1wpLyxjOlsic2VsZiIscixpLG9dfTtyZXR1cm4gYS5jPVtvLGkscl0se2FsaWFzZXM6WyJweSIsImd5cCIsImlweXRob24iXSxrOnQsaTovKDxcL3wtPnxcPyl8PT4vLGM6W3IsaSxvLGUuSENNLHt2Olt7Y046ImZ1bmN0aW9uIixiSzoiZGVmIn0se2NOOiJjbGFzcyIsYks6ImNsYXNzIn1dLGU6LzovLGk6L1skez07XG4sXS8sYzpbZS5VVE0sbix7YjovLT4vLGVXOiEwLGs6Ik5vbmUifV19LHtjTjoibWV0YSIsYjovXltcdCBdKkAvLGU6LyQvfSx7YjovXGIocHJpbnR8ZXhlYylcKC99XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoInJ1c3QiLGZ1bmN0aW9uKGUpe3ZhciB0PSIoW3VpXSg4fDE2fDMyfDY0fDEyOHxzaXplKXxmKDMyfDY0KSk/IixyPSJkcm9wIGk4IGkxNiBpMzIgaTY0IGkxMjggaXNpemUgdTggdTE2IHUzMiB1NjQgdTEyOCB1c2l6ZSBmMzIgZjY0IHN0ciBjaGFyIGJvb2wgQm94IE9wdGlvbiBSZXN1bHQgU3RyaW5nIFZlYyBDb3B5IFNlbmQgU2l6ZWQgU3luYyBEcm9wIEZuIEZuTXV0IEZuT25jZSBUb093bmVkIENsb25lIERlYnVnIFBhcnRpYWxFcSBQYXJ0aWFsT3JkIEVxIE9yZCBBc1JlZiBBc011dCBJbnRvIEZyb20gRGVmYXVsdCBJdGVyYXRvciBFeHRlbmQgSW50b0l0ZXJhdG9yIERvdWJsZUVuZGVkSXRlcmF0b3IgRXhhY3RTaXplSXRlcmF0b3IgU2xpY2VDb25jYXRFeHQgVG9TdHJpbmcgYXNzZXJ0ISBhc3NlcnRfZXEhIGJpdGZsYWdzISBieXRlcyEgY2ZnISBjb2whIGNvbmNhdCEgY29uY2F0X2lkZW50cyEgZGVidWdfYXNzZXJ0ISBkZWJ1Z19hc3NlcnRfZXEhIGVudiEgcGFuaWMhIGZpbGUhIGZvcm1hdCEgZm9ybWF0X2FyZ3MhIGluY2x1ZGVfYmluISBpbmNsdWRlX3N0ciEgbGluZSEgbG9jYWxfZGF0YV9rZXkhIG1vZHVsZV9wYXRoISBvcHRpb25fZW52ISBwcmludCEgcHJpbnRsbiEgc2VsZWN0ISBzdHJpbmdpZnkhIHRyeSEgdW5pbXBsZW1lbnRlZCEgdW5yZWFjaGFibGUhIHZlYyEgd3JpdGUhIHdyaXRlbG4hIG1hY3JvX3J1bGVzISBhc3NlcnRfbmUhIGRlYnVnX2Fzc2VydF9uZSEiO3JldHVybnthbGlhc2VzOlsicnMiXSxrOntrZXl3b3JkOiJhYnN0cmFjdCBhcyBhc3luYyBhd2FpdCBiZWNvbWUgYm94IGJyZWFrIGNvbnN0IGNvbnRpbnVlIGNyYXRlIGRvIGR5biBlbHNlIGVudW0gZXh0ZXJuIGZhbHNlIGZpbmFsIGZuIGZvciBpZiBpbXBsIGluIGxldCBsb29wIG1hY3JvIG1hdGNoIG1vZCBtb3ZlIG11dCBvdmVycmlkZSBwcml2IHB1YiByZWYgcmV0dXJuIHNlbGYgU2VsZiBzdGF0aWMgc3RydWN0IHN1cGVyIHRyYWl0IHRydWUgdHJ5IHR5cGUgdHlwZW9mIHVuc2FmZSB1bnNpemVkIHVzZSB2aXJ0dWFsIHdoZXJlIHdoaWxlIHlpZWxkIixsaXRlcmFsOiJ0cnVlIGZhbHNlIFNvbWUgTm9uZSBPayBFcnIiLGJ1aWx0X2luOnJ9LGw6ZS5JUisiIT8iLGk6IjwvIixjOltlLkNMQ00sZS5DKCIvXFwqIiwiXFwqLyIse2M6WyJzZWxmIl19KSxlLmluaGVyaXQoZS5RU00se2I6L2I/Ii8saTpudWxsfSkse2NOOiJzdHJpbmciLHY6W3tiOi9yKCMqKSIoLnxcbikqPyJcMSg/ISMpL30se2I6L2I/J1xcPyh4XHd7Mn18dVx3ezR9fFVcd3s4fXwuKScvfV19LHtjTjoic3ltYm9sIixiOi8nW2EtekEtWl9dW2EtekEtWjAtOV9dKi99LHtjTjoibnVtYmVyIix2Olt7YjoiXFxiMGIoWzAxX10rKSIrdH0se2I6IlxcYjBvKFswLTdfXSspIit0fSx7YjoiXFxiMHgoW0EtRmEtZjAtOV9dKykiK3R9LHtiOiJcXGIoXFxkW1xcZF9dKihcXC5bMC05X10rKT8oW2VFXVsrLV0/WzAtOV9dKyk/KSIrdH1dLHI6MH0se2NOOiJmdW5jdGlvbiIsYks6ImZuIixlOiIoXFwofDwpIixlRTohMCxjOltlLlVUTV19LHtjTjoibWV0YSIsYjoiI1xcIT9cXFsiLGU6IlxcXSIsYzpbe2NOOiJtZXRhLXN0cmluZyIsYjovIi8sZTovIi99XX0se2NOOiJjbGFzcyIsYks6InR5cGUiLGU6IjsiLGM6W2UuaW5oZXJpdChlLlVUTSx7ZW5kc1BhcmVudDohMH0pXSxpOiJcXFMifSx7Y046ImNsYXNzIixiSzoidHJhaXQgZW51bSBzdHJ1Y3QgdW5pb24iLGU6InsiLGM6W2UuaW5oZXJpdChlLlVUTSx7ZW5kc1BhcmVudDohMH0pXSxpOiJbXFx3XFxkXSJ9LHtiOmUuSVIrIjo6IixrOntidWlsdF9pbjpyfX0se2I6Ii0+In1dfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgic3FsIixmdW5jdGlvbihlKXt2YXIgdD1lLkMoIi0tIiwiJCIpO3JldHVybntjSTohMCxpOi9bPD57fSpdLyxjOlt7Yks6ImJlZ2luIGVuZCBzdGFydCBjb21taXQgcm9sbGJhY2sgc2F2ZXBvaW50IGxvY2sgYWx0ZXIgY3JlYXRlIGRyb3AgcmVuYW1lIGNhbGwgZGVsZXRlIGRvIGhhbmRsZXIgaW5zZXJ0IGxvYWQgcmVwbGFjZSBzZWxlY3QgdHJ1bmNhdGUgdXBkYXRlIHNldCBzaG93IHByYWdtYSBncmFudCBtZXJnZSBkZXNjcmliZSB1c2UgZXhwbGFpbiBoZWxwIGRlY2xhcmUgcHJlcGFyZSBleGVjdXRlIGRlYWxsb2NhdGUgcmVsZWFzZSB1bmxvY2sgcHVyZ2UgcmVzZXQgY2hhbmdlIHN0b3AgYW5hbHl6ZSBjYWNoZSBmbHVzaCBvcHRpbWl6ZSByZXBhaXIga2lsbCBpbnN0YWxsIHVuaW5zdGFsbCBjaGVja3N1bSByZXN0b3JlIGNoZWNrIGJhY2t1cCByZXZva2UgY29tbWVudCB2YWx1ZXMgd2l0aCIsZTovOy8sZVc6ITAsbDovW1x3XC5dKy8sazp7a2V5d29yZDoiYXMgYWJvcnQgYWJzIGFic29sdXRlIGFjYyBhY2NlIGFjY2VwIGFjY2VwdCBhY2Nlc3MgYWNjZXNzZWQgYWNjZXNzaWJsZSBhY2NvdW50IGFjb3MgYWN0aW9uIGFjdGl2YXRlIGFkZCBhZGR0aW1lIGFkbWluIGFkbWluaXN0ZXIgYWR2YW5jZWQgYWR2aXNlIGFlc19kZWNyeXB0IGFlc19lbmNyeXB0IGFmdGVyIGFnZW50IGFnZ3JlZ2F0ZSBhbGkgYWxpYSBhbGlhcyBhbGwgYWxsb2NhdGUgYWxsb3cgYWx0ZXIgYWx3YXlzIGFuYWx5emUgYW5jaWxsYXJ5IGFuZCBhbnRpIGFueSBhbnlkYXRhIGFueWRhdGFzZXQgYW55c2NoZW1hIGFueXR5cGUgYXBwbHkgYXJjaGl2ZSBhcmNoaXZlZCBhcmNoaXZlbG9nIGFyZSBhcyBhc2MgYXNjaWkgYXNpbiBhc3NlbWJseSBhc3NlcnRpb24gYXNzb2NpYXRlIGFzeW5jaHJvbm91cyBhdCBhdGFuIGF0bjIgYXR0ciBhdHRyaSBhdHRyaWIgYXR0cmlidSBhdHRyaWJ1dCBhdHRyaWJ1dGUgYXR0cmlidXRlcyBhdWRpdCBhdXRoZW50aWNhdGVkIGF1dGhlbnRpY2F0aW9uIGF1dGhpZCBhdXRob3JzIGF1dG8gYXV0b2FsbG9jYXRlIGF1dG9kYmxpbmsgYXV0b2V4dGVuZCBhdXRvbWF0aWMgYXZhaWxhYmlsaXR5IGF2ZyBiYWNrdXAgYmFkZmlsZSBiYXNpY2ZpbGUgYmVmb3JlIGJlZ2luIGJlZ2lubmluZyBiZW5jaG1hcmsgYmV0d2VlbiBiZmlsZSBiZmlsZV9iYXNlIGJpZyBiaWdmaWxlIGJpbiBiaW5hcnlfZG91YmxlIGJpbmFyeV9mbG9hdCBiaW5sb2cgYml0X2FuZCBiaXRfY291bnQgYml0X2xlbmd0aCBiaXRfb3IgYml0X3hvciBiaXRtYXAgYmxvYl9iYXNlIGJsb2NrIGJsb2Nrc2l6ZSBib2R5IGJvdGggYm91bmQgYnVja2V0IGJ1ZmZlcl9jYWNoZSBidWZmZXJfcG9vbCBidWlsZCBidWxrIGJ5IGJ5dGUgYnl0ZW9yZGVybWFyayBieXRlcyBjYWNoZSBjYWNoaW5nIGNhbGwgY2FsbGluZyBjYW5jZWwgY2FwYWNpdHkgY2FzY2FkZSBjYXNjYWRlZCBjYXNlIGNhc3QgY2F0YWxvZyBjYXRlZ29yeSBjZWlsIGNlaWxpbmcgY2hhaW4gY2hhbmdlIGNoYW5nZWQgY2hhcl9iYXNlIGNoYXJfbGVuZ3RoIGNoYXJhY3Rlcl9sZW5ndGggY2hhcmFjdGVycyBjaGFyYWN0ZXJzZXQgY2hhcmluZGV4IGNoYXJzZXQgY2hhcnNldGZvcm0gY2hhcnNldGlkIGNoZWNrIGNoZWNrc3VtIGNoZWNrc3VtX2FnZyBjaGlsZCBjaG9vc2UgY2hyIGNodW5rIGNsYXNzIGNsZWFudXAgY2xlYXIgY2xpZW50IGNsb2IgY2xvYl9iYXNlIGNsb25lIGNsb3NlIGNsdXN0ZXJfaWQgY2x1c3Rlcl9wcm9iYWJpbGl0eSBjbHVzdGVyX3NldCBjbHVzdGVyaW5nIGNvYWxlc2NlIGNvZXJjaWJpbGl0eSBjb2wgY29sbGF0ZSBjb2xsYXRpb24gY29sbGVjdCBjb2x1IGNvbHVtIGNvbHVtbiBjb2x1bW5fdmFsdWUgY29sdW1ucyBjb2x1bW5zX3VwZGF0ZWQgY29tbWVudCBjb21taXQgY29tcGFjdCBjb21wYXRpYmlsaXR5IGNvbXBpbGVkIGNvbXBsZXRlIGNvbXBvc2l0ZV9saW1pdCBjb21wb3VuZCBjb21wcmVzcyBjb21wdXRlIGNvbmNhdCBjb25jYXRfd3MgY29uY3VycmVudCBjb25maXJtIGNvbm4gY29ubmVjIGNvbm5lY3QgY29ubmVjdF9ieV9pc2N5Y2xlIGNvbm5lY3RfYnlfaXNsZWFmIGNvbm5lY3RfYnlfcm9vdCBjb25uZWN0X3RpbWUgY29ubmVjdGlvbiBjb25zaWRlciBjb25zaXN0ZW50IGNvbnN0YW50IGNvbnN0cmFpbnQgY29uc3RyYWludHMgY29uc3RydWN0b3IgY29udGFpbmVyIGNvbnRlbnQgY29udGVudHMgY29udGV4dCBjb250cmlidXRvcnMgY29udHJvbGZpbGUgY29udiBjb252ZXJ0IGNvbnZlcnRfdHogY29yciBjb3JyX2sgY29ycl9zIGNvcnJlc3BvbmRpbmcgY29ycnVwdGlvbiBjb3MgY29zdCBjb3VudCBjb3VudF9iaWcgY291bnRlZCBjb3Zhcl9wb3AgY292YXJfc2FtcCBjcHVfcGVyX2NhbGwgY3B1X3Blcl9zZXNzaW9uIGNyYzMyIGNyZWF0ZSBjcmVhdGlvbiBjcml0aWNhbCBjcm9zcyBjdWJlIGN1bWVfZGlzdCBjdXJkYXRlIGN1cnJlbnQgY3VycmVudF9kYXRlIGN1cnJlbnRfdGltZSBjdXJyZW50X3RpbWVzdGFtcCBjdXJyZW50X3VzZXIgY3Vyc29yIGN1cnRpbWUgY3VzdG9tZGF0dW0gY3ljbGUgZGF0YSBkYXRhYmFzZSBkYXRhYmFzZXMgZGF0YWZpbGUgZGF0YWZpbGVzIGRhdGFsZW5ndGggZGF0ZV9hZGQgZGF0ZV9jYWNoZSBkYXRlX2Zvcm1hdCBkYXRlX3N1YiBkYXRlYWRkIGRhdGVkaWZmIGRhdGVmcm9tcGFydHMgZGF0ZW5hbWUgZGF0ZXBhcnQgZGF0ZXRpbWUyZnJvbXBhcnRzIGRheSBkYXlfdG9fc2Vjb25kIGRheW5hbWUgZGF5b2Ztb250aCBkYXlvZndlZWsgZGF5b2Z5ZWFyIGRheXMgZGJfcm9sZV9jaGFuZ2UgZGJ0aW1lem9uZSBkZGwgZGVhbGxvY2F0ZSBkZWNsYXJlIGRlY29kZSBkZWNvbXBvc2UgZGVjcmVtZW50IGRlY3J5cHQgZGVkdXBsaWNhdGUgZGVmIGRlZmEgZGVmYXUgZGVmYXVsIGRlZmF1bHQgZGVmYXVsdHMgZGVmZXJyZWQgZGVmaSBkZWZpbiBkZWZpbmUgZGVncmVlcyBkZWxheWVkIGRlbGVnYXRlIGRlbGV0ZSBkZWxldGVfYWxsIGRlbGltaXRlZCBkZW1hbmQgZGVuc2VfcmFuayBkZXB0aCBkZXF1ZXVlIGRlc19kZWNyeXB0IGRlc19lbmNyeXB0IGRlc19rZXlfZmlsZSBkZXNjIGRlc2NyIGRlc2NyaSBkZXNjcmliIGRlc2NyaWJlIGRlc2NyaXB0b3IgZGV0ZXJtaW5pc3RpYyBkaWFnbm9zdGljcyBkaWZmZXJlbmNlIGRpbWVuc2lvbiBkaXJlY3RfbG9hZCBkaXJlY3RvcnkgZGlzYWJsZSBkaXNhYmxlX2FsbCBkaXNhbGxvdyBkaXNhc3NvY2lhdGUgZGlzY2FyZGZpbGUgZGlzY29ubmVjdCBkaXNrZ3JvdXAgZGlzdGluY3QgZGlzdGluY3Ryb3cgZGlzdHJpYnV0ZSBkaXN0cmlidXRlZCBkaXYgZG8gZG9jdW1lbnQgZG9tYWluIGRvdG5ldCBkb3VibGUgZG93bmdyYWRlIGRyb3AgZHVtcGZpbGUgZHVwbGljYXRlIGR1cmF0aW9uIGVhY2ggZWRpdGlvbiBlZGl0aW9uYWJsZSBlZGl0aW9ucyBlbGVtZW50IGVsbGlwc2lzIGVsc2UgZWxzaWYgZWx0IGVtcHR5IGVuYWJsZSBlbmFibGVfYWxsIGVuY2xvc2VkIGVuY29kZSBlbmNvZGluZyBlbmNyeXB0IGVuZCBlbmQtZXhlYyBlbmRpYW4gZW5mb3JjZWQgZW5naW5lIGVuZ2luZXMgZW5xdWV1ZSBlbnRlcnByaXNlIGVudGl0eWVzY2FwaW5nIGVvbW9udGggZXJyb3IgZXJyb3JzIGVzY2FwZWQgZXZhbG5hbWUgZXZhbHVhdGUgZXZlbnQgZXZlbnRkYXRhIGV2ZW50cyBleGNlcHQgZXhjZXB0aW9uIGV4Y2VwdGlvbnMgZXhjaGFuZ2UgZXhjbHVkZSBleGNsdWRpbmcgZXhlY3UgZXhlY3V0IGV4ZWN1dGUgZXhlbXB0IGV4aXN0cyBleGl0IGV4cCBleHBpcmUgZXhwbGFpbiBleHBsb2RlIGV4cG9ydCBleHBvcnRfc2V0IGV4dGVuZGVkIGV4dGVudCBleHRlcm5hbCBleHRlcm5hbF8xIGV4dGVybmFsXzIgZXh0ZXJuYWxseSBleHRyYWN0IGZhaWxlZCBmYWlsZWRfbG9naW5fYXR0ZW1wdHMgZmFpbG92ZXIgZmFpbHVyZSBmYXIgZmFzdCBmZWF0dXJlX3NldCBmZWF0dXJlX3ZhbHVlIGZldGNoIGZpZWxkIGZpZWxkcyBmaWxlIGZpbGVfbmFtZV9jb252ZXJ0IGZpbGVzeXN0ZW1fbGlrZV9sb2dnaW5nIGZpbmFsIGZpbmlzaCBmaXJzdCBmaXJzdF92YWx1ZSBmaXhlZCBmbGFzaF9jYWNoZSBmbGFzaGJhY2sgZmxvb3IgZmx1c2ggZm9sbG93aW5nIGZvbGxvd3MgZm9yIGZvcmFsbCBmb3JjZSBmb3JlaWduIGZvcm0gZm9ybWEgZm9ybWF0IGZvdW5kIGZvdW5kX3Jvd3MgZnJlZWxpc3QgZnJlZWxpc3RzIGZyZWVwb29scyBmcmVzaCBmcm9tIGZyb21fYmFzZTY0IGZyb21fZGF5cyBmdHAgZnVsbCBmdW5jdGlvbiBnZW5lcmFsIGdlbmVyYXRlZCBnZXQgZ2V0X2Zvcm1hdCBnZXRfbG9jayBnZXRkYXRlIGdldHV0Y2RhdGUgZ2xvYmFsIGdsb2JhbF9uYW1lIGdsb2JhbGx5IGdvIGdvdG8gZ3JhbnQgZ3JhbnRzIGdyZWF0ZXN0IGdyb3VwIGdyb3VwX2NvbmNhdCBncm91cF9pZCBncm91cGluZyBncm91cGluZ19pZCBncm91cHMgZ3RpZF9zdWJ0cmFjdCBndWFyYW50ZWUgZ3VhcmQgaGFuZGxlciBoYXNoIGhhc2hrZXlzIGhhdmluZyBoZWEgaGVhZCBoZWFkaSBoZWFkaW4gaGVhZGluZyBoZWFwIGhlbHAgaGV4IGhpZXJhcmNoeSBoaWdoIGhpZ2hfcHJpb3JpdHkgaG9zdHMgaG91ciBob3VycyBodHRwIGlkIGlkZW50X2N1cnJlbnQgaWRlbnRfaW5jciBpZGVudF9zZWVkIGlkZW50aWZpZWQgaWRlbnRpdHkgaWRsZV90aW1lIGlmIGlmbnVsbCBpZ25vcmUgaWlmIGlsaWtlIGlsbSBpbW1lZGlhdGUgaW1wb3J0IGluIGluY2x1ZGUgaW5jbHVkaW5nIGluY3JlbWVudCBpbmRleCBpbmRleGVzIGluZGV4aW5nIGluZGV4dHlwZSBpbmRpY2F0b3IgaW5kaWNlcyBpbmV0Nl9hdG9uIGluZXQ2X250b2EgaW5ldF9hdG9uIGluZXRfbnRvYSBpbmZpbGUgaW5pdGlhbCBpbml0aWFsaXplZCBpbml0aWFsbHkgaW5pdHJhbnMgaW5tZW1vcnkgaW5uZXIgaW5ub2RiIGlucHV0IGluc2VydCBpbnN0YWxsIGluc3RhbmNlIGluc3RhbnRpYWJsZSBpbnN0ciBpbnRlcmZhY2UgaW50ZXJsZWF2ZWQgaW50ZXJzZWN0IGludG8gaW52YWxpZGF0ZSBpbnZpc2libGUgaXMgaXNfZnJlZV9sb2NrIGlzX2lwdjQgaXNfaXB2NF9jb21wYXQgaXNfbm90IGlzX25vdF9udWxsIGlzX3VzZWRfbG9jayBpc2RhdGUgaXNudWxsIGlzb2xhdGlvbiBpdGVyYXRlIGphdmEgam9pbiBqc29uIGpzb25fZXhpc3RzIGtlZXAga2VlcF9kdXBsaWNhdGVzIGtleSBrZXlzIGtpbGwgbGFuZ3VhZ2UgbGFyZ2UgbGFzdCBsYXN0X2RheSBsYXN0X2luc2VydF9pZCBsYXN0X3ZhbHVlIGxhdGVyYWwgbGF4IGxjYXNlIGxlYWQgbGVhZGluZyBsZWFzdCBsZWF2ZXMgbGVmdCBsZW4gbGVuZ2h0IGxlbmd0aCBsZXNzIGxldmVsIGxldmVscyBsaWJyYXJ5IGxpa2UgbGlrZTIgbGlrZTQgbGlrZWMgbGltaXQgbGluZXMgbGluayBsaXN0IGxpc3RhZ2cgbGl0dGxlIGxuIGxvYWQgbG9hZF9maWxlIGxvYiBsb2JzIGxvY2FsIGxvY2FsdGltZSBsb2NhbHRpbWVzdGFtcCBsb2NhdGUgbG9jYXRvciBsb2NrIGxvY2tlZCBsb2cgbG9nMTAgbG9nMiBsb2dmaWxlIGxvZ2ZpbGVzIGxvZ2dpbmcgbG9naWNhbCBsb2dpY2FsX3JlYWRzX3Blcl9jYWxsIGxvZ29mZiBsb2dvbiBsb2dzIGxvbmcgbG9vcCBsb3cgbG93X3ByaW9yaXR5IGxvd2VyIGxwYWQgbHJ0cmltIGx0cmltIG1haW4gbWFrZV9zZXQgbWFrZWRhdGUgbWFrZXRpbWUgbWFuYWdlZCBtYW5hZ2VtZW50IG1hbnVhbCBtYXAgbWFwcGluZyBtYXNrIG1hc3RlciBtYXN0ZXJfcG9zX3dhaXQgbWF0Y2ggbWF0Y2hlZCBtYXRlcmlhbGl6ZWQgbWF4IG1heGV4dGVudHMgbWF4aW1pemUgbWF4aW5zdGFuY2VzIG1heGxlbiBtYXhsb2dmaWxlcyBtYXhsb2doaXN0b3J5IG1heGxvZ21lbWJlcnMgbWF4c2l6ZSBtYXh0cmFucyBtZDUgbWVhc3VyZXMgbWVkaWFuIG1lZGl1bSBtZW1iZXIgbWVtY29tcHJlc3MgbWVtb3J5IG1lcmdlIG1pY3Jvc2Vjb25kIG1pZCBtaWdyYXRpb24gbWluIG1pbmV4dGVudHMgbWluaW11bSBtaW5pbmcgbWludXMgbWludXRlIG1pbnV0ZXMgbWludmFsdWUgbWlzc2luZyBtb2QgbW9kZSBtb2RlbCBtb2RpZmljYXRpb24gbW9kaWZ5IG1vZHVsZSBtb25pdG9yaW5nIG1vbnRoIG1vbnRocyBtb3VudCBtb3ZlIG1vdmVtZW50IG11bHRpc2V0IG11dGV4IG5hbWUgbmFtZV9jb25zdCBuYW1lcyBuYW4gbmF0aW9uYWwgbmF0aXZlIG5hdHVyYWwgbmF2IG5jaGFyIG5jbG9iIG5lc3RlZCBuZXZlciBuZXcgbmV3bGluZSBuZXh0IG5leHR2YWwgbm8gbm9fd3JpdGVfdG9fYmlubG9nIG5vYXJjaGl2ZWxvZyBub2F1ZGl0IG5vYmFkZmlsZSBub2NoZWNrIG5vY29tcHJlc3Mgbm9jb3B5IG5vY3ljbGUgbm9kZWxheSBub2Rpc2NhcmRmaWxlIG5vZW50aXR5ZXNjYXBpbmcgbm9ndWFyYW50ZWUgbm9rZWVwIG5vbG9nZmlsZSBub21hcHBpbmcgbm9tYXh2YWx1ZSBub21pbmltaXplIG5vbWludmFsdWUgbm9tb25pdG9yaW5nIG5vbmUgbm9uZWRpdGlvbmFibGUgbm9uc2NoZW1hIG5vb3JkZXIgbm9wciBub3BybyBub3Byb20gbm9wcm9tcCBub3Byb21wdCBub3JlbHkgbm9yZXNldGxvZ3Mgbm9yZXZlcnNlIG5vcm1hbCBub3Jvd2RlcGVuZGVuY2llcyBub3NjaGVtYWNoZWNrIG5vc3dpdGNoIG5vdCBub3RoaW5nIG5vdGljZSBub3RudWxsIG5vdHJpbSBub3ZhbGlkYXRlIG5vdyBub3dhaXQgbnRoX3ZhbHVlIG51bGxpZiBudWxscyBudW0gbnVtYiBudW1iZSBudmFyY2hhciBudmFyY2hhcjIgb2JqZWN0IG9jaWNvbGwgb2NpZGF0ZSBvY2lkYXRldGltZSBvY2lkdXJhdGlvbiBvY2lpbnRlcnZhbCBvY2lsb2Jsb2NhdG9yIG9jaW51bWJlciBvY2lyZWYgb2NpcmVmY3Vyc29yIG9jaXJvd2lkIG9jaXN0cmluZyBvY2l0eXBlIG9jdCBvY3RldF9sZW5ndGggb2Ygb2ZmIG9mZmxpbmUgb2Zmc2V0IG9pZCBvaWRpbmRleCBvbGQgb24gb25saW5lIG9ubHkgb3BhcXVlIG9wZW4gb3BlcmF0aW9ucyBvcGVyYXRvciBvcHRpbWFsIG9wdGltaXplIG9wdGlvbiBvcHRpb25hbGx5IG9yIG9yYWNsZSBvcmFjbGVfZGF0ZSBvcmFkYXRhIG9yZCBvcmRhdWRpbyBvcmRkaWNvbSBvcmRkb2Mgb3JkZXIgb3JkaW1hZ2Ugb3JkaW5hbGl0eSBvcmR2aWRlbyBvcmdhbml6YXRpb24gb3JsYW55IG9ybHZhcnkgb3V0IG91dGVyIG91dGZpbGUgb3V0bGluZSBvdXRwdXQgb3ZlciBvdmVyZmxvdyBvdmVycmlkaW5nIHBhY2thZ2UgcGFkIHBhcmFsbGVsIHBhcmFsbGVsX2VuYWJsZSBwYXJhbWV0ZXJzIHBhcmVudCBwYXJzZSBwYXJ0aWFsIHBhcnRpdGlvbiBwYXJ0aXRpb25zIHBhc2NhbCBwYXNzaW5nIHBhc3N3b3JkIHBhc3N3b3JkX2dyYWNlX3RpbWUgcGFzc3dvcmRfbG9ja190aW1lIHBhc3N3b3JkX3JldXNlX21heCBwYXNzd29yZF9yZXVzZV90aW1lIHBhc3N3b3JkX3ZlcmlmeV9mdW5jdGlvbiBwYXRjaCBwYXRoIHBhdGluZGV4IHBjdGluY3JlYXNlIHBjdHRocmVzaG9sZCBwY3R1c2VkIHBjdHZlcnNpb24gcGVyY2VudCBwZXJjZW50X3JhbmsgcGVyY2VudGlsZV9jb250IHBlcmNlbnRpbGVfZGlzYyBwZXJmb3JtYW5jZSBwZXJpb2QgcGVyaW9kX2FkZCBwZXJpb2RfZGlmZiBwZXJtYW5lbnQgcGh5c2ljYWwgcGkgcGlwZSBwaXBlbGluZWQgcGl2b3QgcGx1Z2dhYmxlIHBsdWdpbiBwb2xpY3kgcG9zaXRpb24gcG9zdF90cmFuc2FjdGlvbiBwb3cgcG93ZXIgcHJhZ21hIHByZWJ1aWx0IHByZWNlZGVzIHByZWNlZGluZyBwcmVjaXNpb24gcHJlZGljdGlvbiBwcmVkaWN0aW9uX2Nvc3QgcHJlZGljdGlvbl9kZXRhaWxzIHByZWRpY3Rpb25fcHJvYmFiaWxpdHkgcHJlZGljdGlvbl9zZXQgcHJlcGFyZSBwcmVzZW50IHByZXNlcnZlIHByaW9yIHByaW9yaXR5IHByaXZhdGUgcHJpdmF0ZV9zZ2EgcHJpdmlsZWdlcyBwcm9jZWR1cmFsIHByb2NlZHVyZSBwcm9jZWR1cmVfYW5hbHl6ZSBwcm9jZXNzbGlzdCBwcm9maWxlcyBwcm9qZWN0IHByb21wdCBwcm90ZWN0aW9uIHB1YmxpYyBwdWJsaXNoaW5nc2VydmVybmFtZSBwdXJnZSBxdWFydGVyIHF1ZXJ5IHF1aWNrIHF1aWVzY2UgcXVvdGEgcXVvdGVuYW1lIHJhZGlhbnMgcmFpc2UgcmFuZCByYW5nZSByYW5rIHJhdyByZWFkIHJlYWRzIHJlYWRzaXplIHJlYnVpbGQgcmVjb3JkIHJlY29yZHMgcmVjb3ZlciByZWNvdmVyeSByZWN1cnNpdmUgcmVjeWNsZSByZWRvIHJlZHVjZWQgcmVmIHJlZmVyZW5jZSByZWZlcmVuY2VkIHJlZmVyZW5jZXMgcmVmZXJlbmNpbmcgcmVmcmVzaCByZWdleHBfbGlrZSByZWdpc3RlciByZWdyX2F2Z3ggcmVncl9hdmd5IHJlZ3JfY291bnQgcmVncl9pbnRlcmNlcHQgcmVncl9yMiByZWdyX3Nsb3BlIHJlZ3Jfc3h4IHJlZ3Jfc3h5IHJlamVjdCByZWtleSByZWxhdGlvbmFsIHJlbGF0aXZlIHJlbGF5bG9nIHJlbGVhc2UgcmVsZWFzZV9sb2NrIHJlbGllc19vbiByZWxvY2F0ZSByZWx5IHJlbSByZW1haW5kZXIgcmVuYW1lIHJlcGFpciByZXBlYXQgcmVwbGFjZSByZXBsaWNhdGUgcmVwbGljYXRpb24gcmVxdWlyZWQgcmVzZXQgcmVzZXRsb2dzIHJlc2l6ZSByZXNvdXJjZSByZXNwZWN0IHJlc3RvcmUgcmVzdHJpY3RlZCByZXN1bHQgcmVzdWx0X2NhY2hlIHJlc3VtYWJsZSByZXN1bWUgcmV0ZW50aW9uIHJldHVybiByZXR1cm5pbmcgcmV0dXJucyByZXVzZSByZXZlcnNlIHJldm9rZSByaWdodCBybGlrZSByb2xlIHJvbGVzIHJvbGxiYWNrIHJvbGxpbmcgcm9sbHVwIHJvdW5kIHJvdyByb3dfY291bnQgcm93ZGVwZW5kZW5jaWVzIHJvd2lkIHJvd251bSByb3dzIHJ0cmltIHJ1bGVzIHNhZmUgc2FsdCBzYW1wbGUgc2F2ZSBzYXZlcG9pbnQgc2IxIHNiMiBzYjQgc2NhbiBzY2hlbWEgc2NoZW1hY2hlY2sgc2NuIHNjb3BlIHNjcm9sbCBzZG9fZ2VvcmFzdGVyIHNkb190b3BvX2dlb21ldHJ5IHNlYXJjaCBzZWNfdG9fdGltZSBzZWNvbmQgc2Vjb25kcyBzZWN0aW9uIHNlY3VyZWZpbGUgc2VjdXJpdHkgc2VlZCBzZWdtZW50IHNlbGVjdCBzZWxmIHNlbWkgc2VxdWVuY2Ugc2VxdWVudGlhbCBzZXJpYWxpemFibGUgc2VydmVyIHNlcnZlcmVycm9yIHNlc3Npb24gc2Vzc2lvbl91c2VyIHNlc3Npb25zX3Blcl91c2VyIHNldCBzZXRzIHNldHRpbmdzIHNoYSBzaGExIHNoYTIgc2hhcmUgc2hhcmVkIHNoYXJlZF9wb29sIHNob3J0IHNob3cgc2hyaW5rIHNodXRkb3duIHNpX2F2ZXJhZ2Vjb2xvciBzaV9jb2xvcmhpc3RvZ3JhbSBzaV9mZWF0dXJlbGlzdCBzaV9wb3NpdGlvbmFsY29sb3Igc2lfc3RpbGxpbWFnZSBzaV90ZXh0dXJlIHNpYmxpbmdzIHNpZCBzaWduIHNpbiBzaXplIHNpemVfdCBzaXplcyBza2lwIHNsYXZlIHNsZWVwIHNtYWxsZGF0ZXRpbWVmcm9tcGFydHMgc21hbGxmaWxlIHNuYXBzaG90IHNvbWUgc29uYW1lIHNvcnQgc291bmRleCBzb3VyY2Ugc3BhY2Ugc3BhcnNlIHNwZmlsZSBzcGxpdCBzcWwgc3FsX2JpZ19yZXN1bHQgc3FsX2J1ZmZlcl9yZXN1bHQgc3FsX2NhY2hlIHNxbF9jYWxjX2ZvdW5kX3Jvd3Mgc3FsX3NtYWxsX3Jlc3VsdCBzcWxfdmFyaWFudF9wcm9wZXJ0eSBzcWxjb2RlIHNxbGRhdGEgc3FsZXJyb3Igc3FsbmFtZSBzcWxzdGF0ZSBzcXJ0IHNxdWFyZSBzdGFuZGFsb25lIHN0YW5kYnkgc3RhcnQgc3RhcnRpbmcgc3RhcnR1cCBzdGF0ZW1lbnQgc3RhdGljIHN0YXRpc3RpY3Mgc3RhdHNfYmlub21pYWxfdGVzdCBzdGF0c19jcm9zc3RhYiBzdGF0c19rc190ZXN0IHN0YXRzX21vZGUgc3RhdHNfbXdfdGVzdCBzdGF0c19vbmVfd2F5X2Fub3ZhIHN0YXRzX3RfdGVzdF8gc3RhdHNfdF90ZXN0X2luZGVwIHN0YXRzX3RfdGVzdF9vbmUgc3RhdHNfdF90ZXN0X3BhaXJlZCBzdGF0c193c3JfdGVzdCBzdGF0dXMgc3RkIHN0ZGRldiBzdGRkZXZfcG9wIHN0ZGRldl9zYW1wIHN0ZGV2IHN0b3Agc3RvcmFnZSBzdG9yZSBzdG9yZWQgc3RyIHN0cl90b19kYXRlIHN0cmFpZ2h0X2pvaW4gc3RyY21wIHN0cmljdCBzdHJpbmcgc3RydWN0IHN0dWZmIHN0eWxlIHN1YmRhdGUgc3VicGFydGl0aW9uIHN1YnBhcnRpdGlvbnMgc3Vic3RpdHV0YWJsZSBzdWJzdHIgc3Vic3RyaW5nIHN1YnRpbWUgc3VidHJpbmdfaW5kZXggc3VidHlwZSBzdWNjZXNzIHN1bSBzdXNwZW5kIHN3aXRjaCBzd2l0Y2hvZmZzZXQgc3dpdGNob3ZlciBzeW5jIHN5bmNocm9ub3VzIHN5bm9ueW0gc3lzIHN5c194bWxhZ2cgc3lzYXNtIHN5c2F1eCBzeXNkYXRlIHN5c2RhdGV0aW1lb2Zmc2V0IHN5c2RiYSBzeXNvcGVyIHN5c3RlbSBzeXN0ZW1fdXNlciBzeXN1dGNkYXRldGltZSB0YWJsZSB0YWJsZXMgdGFibGVzcGFjZSB0YWJsZXNhbXBsZSB0YW4gdGRvIHRlbXBsYXRlIHRlbXBvcmFyeSB0ZXJtaW5hdGVkIHRlcnRpYXJ5X3dlaWdodHMgdGVzdCB0aGFuIHRoZW4gdGhyZWFkIHRocm91Z2ggdGllciB0aWVzIHRpbWUgdGltZV9mb3JtYXQgdGltZV96b25lIHRpbWVkaWZmIHRpbWVmcm9tcGFydHMgdGltZW91dCB0aW1lc3RhbXAgdGltZXN0YW1wYWRkIHRpbWVzdGFtcGRpZmYgdGltZXpvbmVfYWJiciB0aW1lem9uZV9taW51dGUgdGltZXpvbmVfcmVnaW9uIHRvIHRvX2Jhc2U2NCB0b19kYXRlIHRvX2RheXMgdG9fc2Vjb25kcyB0b2RhdGV0aW1lb2Zmc2V0IHRyYWNlIHRyYWNraW5nIHRyYW5zYWN0aW9uIHRyYW5zYWN0aW9uYWwgdHJhbnNsYXRlIHRyYW5zbGF0aW9uIHRyZWF0IHRyaWdnZXIgdHJpZ2dlcl9uZXN0bGV2ZWwgdHJpZ2dlcnMgdHJpbSB0cnVuY2F0ZSB0cnlfY2FzdCB0cnlfY29udmVydCB0cnlfcGFyc2UgdHlwZSB1YjEgdWIyIHViNCB1Y2FzZSB1bmFyY2hpdmVkIHVuYm91bmRlZCB1bmNvbXByZXNzIHVuZGVyIHVuZG8gdW5oZXggdW5pY29kZSB1bmlmb3JtIHVuaW5zdGFsbCB1bmlvbiB1bmlxdWUgdW5peF90aW1lc3RhbXAgdW5rbm93biB1bmxpbWl0ZWQgdW5sb2NrIHVubmVzdCB1bnBpdm90IHVucmVjb3ZlcmFibGUgdW5zYWZlIHVuc2lnbmVkIHVudGlsIHVudHJ1c3RlZCB1bnVzYWJsZSB1bnVzZWQgdXBkYXRlIHVwZGF0ZWQgdXBncmFkZSB1cHBlZCB1cHBlciB1cHNlcnQgdXJsIHVyb3dpZCB1c2FibGUgdXNhZ2UgdXNlIHVzZV9zdG9yZWRfb3V0bGluZXMgdXNlciB1c2VyX2RhdGEgdXNlcl9yZXNvdXJjZXMgdXNlcnMgdXNpbmcgdXRjX2RhdGUgdXRjX3RpbWVzdGFtcCB1dWlkIHV1aWRfc2hvcnQgdmFsaWRhdGUgdmFsaWRhdGVfcGFzc3dvcmRfc3RyZW5ndGggdmFsaWRhdGlvbiB2YWxpc3QgdmFsdWUgdmFsdWVzIHZhciB2YXJfc2FtcCB2YXJjaGFyYyB2YXJpIHZhcmlhIHZhcmlhYiB2YXJpYWJsIHZhcmlhYmxlIHZhcmlhYmxlcyB2YXJpYW5jZSB2YXJwIHZhcnJhdyB2YXJyYXdjIHZhcnJheSB2ZXJpZnkgdmVyc2lvbiB2ZXJzaW9ucyB2aWV3IHZpcnR1YWwgdmlzaWJsZSB2b2lkIHdhaXQgd2FsbGV0IHdhcm5pbmcgd2FybmluZ3Mgd2VlayB3ZWVrZGF5IHdlZWtvZnllYXIgd2VsbGZvcm1lZCB3aGVuIHdoZW5lIHdoZW5ldiB3aGVuZXZlIHdoZW5ldmVyIHdoZXJlIHdoaWxlIHdoaXRlc3BhY2Ugd2luZG93IHdpdGggd2l0aGluIHdpdGhvdXQgd29yayB3cmFwcGVkIHhkYiB4bWwgeG1sYWdnIHhtbGF0dHJpYnV0ZXMgeG1sY2FzdCB4bWxjb2xhdHR2YWwgeG1sZWxlbWVudCB4bWxleGlzdHMgeG1sZm9yZXN0IHhtbGluZGV4IHhtbG5hbWVzcGFjZXMgeG1scGkgeG1scXVlcnkgeG1scm9vdCB4bWxzY2hlbWEgeG1sc2VyaWFsaXplIHhtbHRhYmxlIHhtbHR5cGUgeG9yIHllYXIgeWVhcl90b19tb250aCB5ZWFycyB5ZWFyd2VlayIsbGl0ZXJhbDoidHJ1ZSBmYWxzZSBudWxsIHVua25vd24iLGJ1aWx0X2luOiJhcnJheSBiaWdpbnQgYmluYXJ5IGJpdCBibG9iIGJvb2wgYm9vbGVhbiBjaGFyIGNoYXJhY3RlciBkYXRlIGRlYyBkZWNpbWFsIGZsb2F0IGludCBpbnQ4IGludGVnZXIgaW50ZXJ2YWwgbnVtYmVyIG51bWVyaWMgcmVhbCByZWNvcmQgc2VyaWFsIHNlcmlhbDggc21hbGxpbnQgdGV4dCB0aW1lIHRpbWVzdGFtcCB0aW55aW50IHZhcmNoYXIgdmFyeWluZyB2b2lkIn0sYzpbe2NOOiJzdHJpbmciLGI6IiciLGU6IiciLGM6W2UuQkUse2I6IicnIn1dfSx7Y046InN0cmluZyIsYjonIicsZTonIicsYzpbZS5CRSx7YjonIiInfV19LHtjTjoic3RyaW5nIixiOiJgIixlOiJgIixjOltlLkJFXX0sZS5DTk0sZS5DQkNNLHQsZS5IQ01dfSxlLkNCQ00sdCxlLkhDTV19fSksby5yZWdpc3Rlckxhbmd1YWdlKCJzd2lmdCIsZnVuY3Rpb24oZSl7dmFyIHQ9e2tleXdvcmQ6IiNhdmFpbGFibGUgI2NvbG9yTGl0ZXJhbCAjY29sdW1uICNlbHNlICNlbHNlaWYgI2VuZGlmICNmaWxlICNmaWxlTGl0ZXJhbCAjZnVuY3Rpb24gI2lmICNpbWFnZUxpdGVyYWwgI2xpbmUgI3NlbGVjdG9yICNzb3VyY2VMb2NhdGlvbiBfIF9fQ09MVU1OX18gX19GSUxFX18gX19GVU5DVElPTl9fIF9fTElORV9fIEFueSBhcyBhcyEgYXM/IGFzc29jaWF0ZWR0eXBlIGFzc29jaWF0aXZpdHkgYnJlYWsgY2FzZSBjYXRjaCBjbGFzcyBjb250aW51ZSBjb252ZW5pZW5jZSBkZWZhdWx0IGRlZmVyIGRlaW5pdCBkaWRTZXQgZG8gZHluYW1pYyBkeW5hbWljVHlwZSBlbHNlIGVudW0gZXh0ZW5zaW9uIGZhbGx0aHJvdWdoIGZhbHNlIGZpbGVwcml2YXRlIGZpbmFsIGZvciBmdW5jIGdldCBndWFyZCBpZiBpbXBvcnQgaW4gaW5kaXJlY3QgaW5maXggaW5pdCBpbm91dCBpbnRlcm5hbCBpcyBsYXp5IGxlZnQgbGV0IG11dGF0aW5nIG5pbCBub25lIG5vbm11dGF0aW5nIG9wZW4gb3BlcmF0b3Igb3B0aW9uYWwgb3ZlcnJpZGUgcG9zdGZpeCBwcmVjZWRlbmNlIHByZWZpeCBwcml2YXRlIHByb3RvY29sIFByb3RvY29sIHB1YmxpYyByZXBlYXQgcmVxdWlyZWQgcmV0aHJvd3MgcmV0dXJuIHJpZ2h0IHNlbGYgU2VsZiBzZXQgc3RhdGljIHN0cnVjdCBzdWJzY3JpcHQgc3VwZXIgc3dpdGNoIHRocm93IHRocm93cyB0cnVlIHRyeSB0cnkhIHRyeT8gVHlwZSB0eXBlYWxpYXMgdW5vd25lZCB2YXIgd2VhayB3aGVyZSB3aGlsZSB3aWxsU2V0IixsaXRlcmFsOiJ0cnVlIGZhbHNlIG5pbCIsYnVpbHRfaW46ImFicyBhZHZhbmNlIGFsaWdub2YgYWxpZ25vZlZhbHVlIGFueUdlbmVyYXRvciBhc3NlcnQgYXNzZXJ0aW9uRmFpbHVyZSBicmlkZ2VGcm9tT2JqZWN0aXZlQyBicmlkZ2VGcm9tT2JqZWN0aXZlQ1VuY29uZGl0aW9uYWwgYnJpZGdlVG9PYmplY3RpdmVDIGJyaWRnZVRvT2JqZWN0aXZlQ1VuY29uZGl0aW9uYWwgYyBjb250YWlucyBjb3VudCBjb3VudEVsZW1lbnRzIGNvdW50TGVhZGluZ1plcm9zIGRlYnVnUHJpbnQgZGVidWdQcmludGxuIGRpc3RhbmNlIGRyb3BGaXJzdCBkcm9wTGFzdCBkdW1wIGVuY29kZUJpdHNBc1dvcmRzIGVudW1lcmF0ZSBlcXVhbCBmYXRhbEVycm9yIGZpbHRlciBmaW5kIGdldEJyaWRnZWRPYmplY3RpdmVDVHlwZSBnZXRWYUxpc3QgaW5kaWNlcyBpbnNlcnRpb25Tb3J0IGlzQnJpZGdlZFRvT2JqZWN0aXZlQyBpc0JyaWRnZWRWZXJiYXRpbVRvT2JqZWN0aXZlQyBpc1VuaXF1ZWx5UmVmZXJlbmNlZCBpc1VuaXF1ZWx5UmVmZXJlbmNlZE5vbk9iakMgam9pbiBsYXp5IGxleGljb2dyYXBoaWNhbENvbXBhcmUgbWFwIG1heCBtYXhFbGVtZW50IG1pbiBtaW5FbGVtZW50IG51bWVyaWNDYXN0IG92ZXJsYXBzIHBhcnRpdGlvbiBwb3NpeCBwcmVjb25kaXRpb24gcHJlY29uZGl0aW9uRmFpbHVyZSBwcmludCBwcmludGxuIHF1aWNrU29ydCByZWFkTGluZSByZWR1Y2UgcmVmbGVjdCByZWludGVycHJldENhc3QgcmV2ZXJzZSByb3VuZFVwVG9BbGlnbm1lbnQgc2l6ZW9mIHNpemVvZlZhbHVlIHNvcnQgc3BsaXQgc3RhcnRzV2l0aCBzdHJpZGUgc3RyaWRlb2Ygc3RyaWRlb2ZWYWx1ZSBzd2FwIHRvU3RyaW5nIHRyYW5zY29kZSB1bmRlcmVzdGltYXRlQ291bnQgdW5zYWZlQWRkcmVzc09mIHVuc2FmZUJpdENhc3QgdW5zYWZlRG93bmNhc3QgdW5zYWZlVW53cmFwIHVuc2FmZVJlZmxlY3Qgd2l0aEV4dGVuZGVkTGlmZXRpbWUgd2l0aE9iamVjdEF0UGx1c1plcm8gd2l0aFVuc2FmZVBvaW50ZXIgd2l0aFVuc2FmZVBvaW50ZXJUb09iamVjdCB3aXRoVW5zYWZlTXV0YWJsZVBvaW50ZXIgd2l0aFVuc2FmZU11dGFibGVQb2ludGVycyB3aXRoVW5zYWZlUG9pbnRlciB3aXRoVW5zYWZlUG9pbnRlcnMgd2l0aFZhTGlzdCB6aXAifSxyPWUuQygiL1xcKiIsIlxcKi8iLHtjOlsic2VsZiJdfSksYT17Y046InN1YnN0IixiOi9cXFwoLyxlOiJcXCkiLGs6dCxjOltdfSxvPXtjTjoic3RyaW5nIixjOltlLkJFLGFdLHY6W3tiOi8iIiIvLGU6LyIiIi99LHtiOi8iLyxlOi8iL31dfSxpPXtjTjoibnVtYmVyIixiOiJcXGIoW1xcZF9dKyhcXC5bXFxkZUVfXSspP3wweFthLWZBLUYwLTlfXSsoXFwuW2EtZkEtRjAtOXBfXSspP3wwYlswMV9dK3wwb1swLTdfXSspXFxiIixyOjB9O3JldHVybiBhLmM9W2ldLHtrOnQsYzpbbyxlLkNMQ00scix7Y046InR5cGUiLGI6IlxcYltBLVpdW1xcd8OALcq4J10qWyE/XSJ9LHtjTjoidHlwZSIsYjoiXFxiW0EtWl1bXFx3w4AtyrgnXSoiLHI6MH0saSx7Y046ImZ1bmN0aW9uIixiSzoiZnVuYyIsZToieyIsZUU6ITAsYzpbZS5pbmhlcml0KGUuVE0se2I6L1tBLVphLXokX11bMC05QS1aYS16JF9dKi99KSx7YjovPC8sZTovPi99LHtjTjoicGFyYW1zIixiOi9cKC8sZTovXCkvLGVuZHNQYXJlbnQ6ITAsazp0LGM6WyJzZWxmIixpLG8sZS5DQkNNLHtiOiI6In1dLGk6L1siJ10vfV0saTovXFt8JS99LHtjTjoiY2xhc3MiLGJLOiJzdHJ1Y3QgcHJvdG9jb2wgY2xhc3MgZXh0ZW5zaW9uIGVudW0iLGs6dCxlOiJcXHsiLGVFOiEwLGM6W2UuaW5oZXJpdChlLlRNLHtiOi9bQS1aYS16JF9dW1x1MDBDMC1cdTAyQjgwLTlBLVphLXokX10qL30pXX0se2NOOiJtZXRhIixiOiIoQGRpc2NhcmRhYmxlUmVzdWx0fEB3YXJuX3VudXNlZF9yZXN1bHR8QGV4cG9ydGVkfEBsYXp5fEBub2VzY2FwZXxATlNDb3B5aW5nfEBOU01hbmFnZWR8QG9iamN8QG9iamNNZW1iZXJzfEBjb252ZW50aW9ufEByZXF1aXJlZHxAbm9yZXR1cm58QElCQWN0aW9ufEBJQkRlc2lnbmFibGV8QElCSW5zcGVjdGFibGV8QElCT3V0bGV0fEBpbmZpeHxAcHJlZml4fEBwb3N0Zml4fEBhdXRvY2xvc3VyZXxAdGVzdGFibGV8QGF2YWlsYWJsZXxAbm9ub2JqY3xATlNBcHBsaWNhdGlvbk1haW58QFVJQXBwbGljYXRpb25NYWluKSJ9LHtiSzoiaW1wb3J0IixlOi8kLyxjOltlLkNMQ00scl19XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoInR5cGVzY3JpcHQiLGZ1bmN0aW9uKGUpe3ZhciB0PSJbQS1aYS16JF9dWzAtOUEtWmEteiRfXSoiLHI9e2tleXdvcmQ6ImluIGlmIGZvciB3aGlsZSBmaW5hbGx5IHZhciBuZXcgZnVuY3Rpb24gZG8gcmV0dXJuIHZvaWQgZWxzZSBicmVhayBjYXRjaCBpbnN0YW5jZW9mIHdpdGggdGhyb3cgY2FzZSBkZWZhdWx0IHRyeSB0aGlzIHN3aXRjaCBjb250aW51ZSB0eXBlb2YgZGVsZXRlIGxldCB5aWVsZCBjb25zdCBjbGFzcyBwdWJsaWMgcHJpdmF0ZSBwcm90ZWN0ZWQgZ2V0IHNldCBzdXBlciBzdGF0aWMgaW1wbGVtZW50cyBlbnVtIGV4cG9ydCBpbXBvcnQgZGVjbGFyZSB0eXBlIG5hbWVzcGFjZSBhYnN0cmFjdCBhcyBmcm9tIGV4dGVuZHMgYXN5bmMgYXdhaXQiLGxpdGVyYWw6InRydWUgZmFsc2UgbnVsbCB1bmRlZmluZWQgTmFOIEluZmluaXR5IixidWlsdF9pbjoiZXZhbCBpc0Zpbml0ZSBpc05hTiBwYXJzZUZsb2F0IHBhcnNlSW50IGRlY29kZVVSSSBkZWNvZGVVUklDb21wb25lbnQgZW5jb2RlVVJJIGVuY29kZVVSSUNvbXBvbmVudCBlc2NhcGUgdW5lc2NhcGUgT2JqZWN0IEZ1bmN0aW9uIEJvb2xlYW4gRXJyb3IgRXZhbEVycm9yIEludGVybmFsRXJyb3IgUmFuZ2VFcnJvciBSZWZlcmVuY2VFcnJvciBTdG9wSXRlcmF0aW9uIFN5bnRheEVycm9yIFR5cGVFcnJvciBVUklFcnJvciBOdW1iZXIgTWF0aCBEYXRlIFN0cmluZyBSZWdFeHAgQXJyYXkgRmxvYXQzMkFycmF5IEZsb2F0NjRBcnJheSBJbnQxNkFycmF5IEludDMyQXJyYXkgSW50OEFycmF5IFVpbnQxNkFycmF5IFVpbnQzMkFycmF5IFVpbnQ4QXJyYXkgVWludDhDbGFtcGVkQXJyYXkgQXJyYXlCdWZmZXIgRGF0YVZpZXcgSlNPTiBJbnRsIGFyZ3VtZW50cyByZXF1aXJlIG1vZHVsZSBjb25zb2xlIHdpbmRvdyBkb2N1bWVudCBhbnkgbnVtYmVyIGJvb2xlYW4gc3RyaW5nIHZvaWQgUHJvbWlzZSJ9LGE9e2NOOiJtZXRhIixiOiJAIit0fSxvPXtiOiJcXCgiLGU6L1wpLyxrOnIsYzpbInNlbGYiLGUuUVNNLGUuQVNNLGUuTk1dfSxpPXtjTjoicGFyYW1zIixiOi9cKC8sZTovXCkvLGVCOiEwLGVFOiEwLGs6cixjOltlLkNMQ00sZS5DQkNNLGEsb119LG49e2NOOiJudW1iZXIiLHY6W3tiOiJcXGIoMFtiQl1bMDFdKykifSx7YjoiXFxiKDBbb09dWzAtN10rKSJ9LHtiOmUuQ05SfV0scjowfSxzPXtjTjoic3Vic3QiLGI6IlxcJFxceyIsZToiXFx9IixrOnIsYzpbXX0sYz17YjoiaHRtbGAiLGU6IiIsc3RhcnRzOntlOiJgIixyRTohMSxjOltlLkJFLHNdLHNMOiJ4bWwifX0sbD17YjoiY3NzYCIsZToiIixzdGFydHM6e2U6ImAiLHJFOiExLGM6W2UuQkUsc10sc0w6ImNzcyJ9fSxOPXtjTjoic3RyaW5nIixiOiJgIixlOiJgIixjOltlLkJFLHNdfTtyZXR1cm4gcy5jPVtlLkFTTSxlLlFTTSxjLGwsTixuLGUuUk1dLHthbGlhc2VzOlsidHMiXSxrOnIsYzpbe2NOOiJtZXRhIixiOi9eXHMqWyciXXVzZSBzdHJpY3RbJyJdL30sZS5BU00sZS5RU00sYyxsLE4sZS5DTENNLGUuQ0JDTSxuLHtiOiIoIitlLlJTUisifFxcYihjYXNlfHJldHVybnx0aHJvdylcXGIpXFxzKiIsazoicmV0dXJuIHRocm93IGNhc2UiLGM6W2UuQ0xDTSxlLkNCQ00sZS5STSx7Y046ImZ1bmN0aW9uIixiOiIoXFwoLio/XFwpfCIrZS5JUisiKVxccyo9PiIsckI6ITAsZToiXFxzKj0+IixjOlt7Y046InBhcmFtcyIsdjpbe2I6ZS5JUn0se2I6L1woXHMqXCkvfSx7YjovXCgvLGU6L1wpLyxlQjohMCxlRTohMCxrOnIsYzpbInNlbGYiLGUuQ0xDTSxlLkNCQ01dfV19XX1dLHI6MH0se2NOOiJmdW5jdGlvbiIsYjoiZnVuY3Rpb24iLGU6L1tceztdLyxlRTohMCxrOnIsYzpbInNlbGYiLGUuaW5oZXJpdChlLlRNLHtiOnR9KSxpXSxpOi8lLyxyOjB9LHtiSzoiY29uc3RydWN0b3IiLGU6L1x7LyxlRTohMCxjOlsic2VsZiIsaV19LHtiOi9tb2R1bGVcLi8sazp7YnVpbHRfaW46Im1vZHVsZSJ9LHI6MH0se2JLOiJtb2R1bGUiLGU6L1x7LyxlRTohMH0se2JLOiJpbnRlcmZhY2UiLGU6L1x7LyxlRTohMCxrOiJpbnRlcmZhY2UgZXh0ZW5kcyJ9LHtiOi9cJFsoLl0vfSx7YjoiXFwuIitlLklSLHI6MH0sYSxvXX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoInZibmV0IixmdW5jdGlvbihlKXtyZXR1cm57YWxpYXNlczpbInZiIl0sY0k6ITAsazp7a2V5d29yZDoiYWRkaGFuZGxlciBhZGRyZXNzb2YgYWxpYXMgYW5kIGFuZGFsc28gYWdncmVnYXRlIGFuc2kgYXMgYXN5bmMgYXNzZW1ibHkgYXV0byBhd2FpdCBiaW5hcnkgYnkgYnlyZWYgYnl2YWwgY2FsbCBjYXNlIGNhdGNoIGNsYXNzIGNvbXBhcmUgY29uc3QgY29udGludWUgY3VzdG9tIGRlY2xhcmUgZGVmYXVsdCBkZWxlZ2F0ZSBkaW0gZGlzdGluY3QgZG8gZWFjaCBlcXVhbHMgZWxzZSBlbHNlaWYgZW5kIGVudW0gZXJhc2UgZXJyb3IgZXZlbnQgZXhpdCBleHBsaWNpdCBmaW5hbGx5IGZvciBmcmllbmQgZnJvbSBmdW5jdGlvbiBnZXQgZ2xvYmFsIGdvdG8gZ3JvdXAgaGFuZGxlcyBpZiBpbXBsZW1lbnRzIGltcG9ydHMgaW4gaW5oZXJpdHMgaW50ZXJmYWNlIGludG8gaXMgaXNmYWxzZSBpc25vdCBpc3RydWUgaXRlcmF0b3Igam9pbiBrZXkgbGV0IGxpYiBsaWtlIGxvb3AgbWUgbWlkIG1vZCBtb2R1bGUgbXVzdGluaGVyaXQgbXVzdG92ZXJyaWRlIG15YmFzZSBteWNsYXNzIG5hbWVzcGFjZSBuYXJyb3dpbmcgbmV3IG5leHQgbm90IG5vdGluaGVyaXRhYmxlIG5vdG92ZXJyaWRhYmxlIG9mIG9mZiBvbiBvcGVyYXRvciBvcHRpb24gb3B0aW9uYWwgb3Igb3JkZXIgb3JlbHNlIG92ZXJsb2FkcyBvdmVycmlkYWJsZSBvdmVycmlkZXMgcGFyYW1hcnJheSBwYXJ0aWFsIHByZXNlcnZlIHByaXZhdGUgcHJvcGVydHkgcHJvdGVjdGVkIHB1YmxpYyByYWlzZWV2ZW50IHJlYWRvbmx5IHJlZGltIHJlbSByZW1vdmVoYW5kbGVyIHJlc3VtZSByZXR1cm4gc2VsZWN0IHNldCBzaGFkb3dzIHNoYXJlZCBza2lwIHN0YXRpYyBzdGVwIHN0b3Agc3RydWN0dXJlIHN0cmljdCBzdWIgc3luY2xvY2sgdGFrZSB0ZXh0IHRoZW4gdGhyb3cgdG8gdHJ5IHVuaWNvZGUgdW50aWwgdXNpbmcgd2hlbiB3aGVyZSB3aGlsZSB3aWRlbmluZyB3aXRoIHdpdGhldmVudHMgd3JpdGVvbmx5IHhvciB5aWVsZCIsYnVpbHRfaW46ImJvb2xlYW4gYnl0ZSBjYm9vbCBjYnl0ZSBjY2hhciBjZGF0ZSBjZGVjIGNkYmwgY2hhciBjaW50IGNsbmcgY29iaiBjc2J5dGUgY3Nob3J0IGNzbmcgY3N0ciBjdHlwZSBkYXRlIGRlY2ltYWwgZGlyZWN0Y2FzdCBkb3VibGUgZ2V0dHlwZSBnZXR4bWxuYW1lc3BhY2UgaWlmIGludGVnZXIgbG9uZyBvYmplY3Qgc2J5dGUgc2hvcnQgc2luZ2xlIHN0cmluZyB0cnljYXN0IHR5cGVvZiB1aW50ZWdlciB1bG9uZyB1c2hvcnQiLGxpdGVyYWw6InRydWUgZmFsc2Ugbm90aGluZyJ9LGk6Ii8vfHt8fXxlbmRpZnxnb3N1Ynx2YXJpYW50fHdlbmR8XlxcJCAiLGM6W2UuaW5oZXJpdChlLlFTTSx7Yzpbe2I6JyIiJ31dfSksZS5DKCInIiwiJCIse3JCOiEwLGM6W3tjTjoiZG9jdGFnIixiOiInJyd8XHgzYyEtLXwtLVx4M2UiLGM6W2UuUFdNXX0se2NOOiJkb2N0YWciLGI6IjwvPyIsZToiPiIsYzpbZS5QV01dfV19KSxlLkNOTSx7Y046Im1ldGEiLGI6IiMiLGU6IiQiLGs6eyJtZXRhLWtleXdvcmQiOiJpZiBlbHNlIGVsc2VpZiBlbmQgcmVnaW9uIGV4dGVybmFsc291cmNlIn19XX19KSxvLnJlZ2lzdGVyTGFuZ3VhZ2UoInJ1YnkiLGZ1bmN0aW9uKGUpe3ZhciB0PSJbYS16QS1aX11cXHcqWyE/PV0/fFstK35dXFxAfDw8fD4+fD1+fD09PT98PD0+fFs8Pl09P3xcXCpcXCp8Wy0vKyVeJip+YHxdfFxcW1xcXT0/IixyPXtrZXl3b3JkOiJhbmQgdGhlbiBkZWZpbmVkIG1vZHVsZSBpbiByZXR1cm4gcmVkbyBpZiBCRUdJTiByZXRyeSBlbmQgZm9yIHNlbGYgd2hlbiBuZXh0IHVudGlsIGRvIGJlZ2luIHVubGVzcyBFTkQgcmVzY3VlIGVsc2UgYnJlYWsgdW5kZWYgbm90IHN1cGVyIGNsYXNzIGNhc2UgcmVxdWlyZSB5aWVsZCBhbGlhcyB3aGlsZSBlbnN1cmUgZWxzaWYgb3IgaW5jbHVkZSBhdHRyX3JlYWRlciBhdHRyX3dyaXRlciBhdHRyX2FjY2Vzc29yIixsaXRlcmFsOiJ0cnVlIGZhbHNlIG5pbCJ9LGE9e2NOOiJkb2N0YWciLGI6IkBbQS1aYS16XSsifSxvPXtiOiIjPCIsZToiPiJ9LGk9W2UuQygiIyIsIiQiLHtjOlthXX0pLGUuQygiXlxcPWJlZ2luIiwiXlxcPWVuZCIse2M6W2FdLHI6MTB9KSxlLkMoIl5fX0VORF9fIiwiXFxuJCIpXSxuPXtjTjoic3Vic3QiLGI6IiNcXHsiLGU6In0iLGs6cn0scz17Y046InN0cmluZyIsYzpbZS5CRSxuXSx2Olt7YjovJy8sZTovJy99LHtiOi8iLyxlOi8iL30se2I6L2AvLGU6L2AvfSx7YjoiJVtxUXdXeF0/XFwoIixlOiJcXCkifSx7YjoiJVtxUXdXeF0/XFxbIixlOiJcXF0ifSx7YjoiJVtxUXdXeF0/eyIsZToifSJ9LHtiOiIlW3FRd1d4XT88IixlOiI+In0se2I6IiVbcVF3V3hdPy8iLGU6Ii8ifSx7YjoiJVtxUXdXeF0/JSIsZToiJSJ9LHtiOiIlW3FRd1d4XT8tIixlOiItIn0se2I6IiVbcVF3V3hdP1xcfCIsZToiXFx8In0se2I6L1xCXD8oXFxcZHsxLDN9fFxceFtBLUZhLWYwLTldezEsMn18XFx1W0EtRmEtZjAtOV17NH18XFw/XFMpXGIvfSx7YjovPDxbLX5dPyc/KFx3KykoPzoufFxuKSo/XG5ccypcMVxiLyxyQjohMCxjOlt7YjovPDxbLX5dPyc/L30se2I6L1x3Ky8sZW5kU2FtZUFzQmVnaW46ITAsYzpbZS5CRSxuXX1dfV19LGM9e2NOOiJwYXJhbXMiLGI6IlxcKCIsZToiXFwpIixlbmRzUGFyZW50OiEwLGs6cn0sbD1bcyxvLHtjTjoiY2xhc3MiLGJLOiJjbGFzcyBtb2R1bGUiLGU6IiR8OyIsaTovPS8sYzpbZS5pbmhlcml0KGUuVE0se2I6IltBLVphLXpfXVxcdyooOjpcXHcrKSooXFw/fFxcISk/In0pLHtiOiI8XFxzKiIsYzpbe2I6IigiK2UuSVIrIjo6KT8iK2UuSVJ9XX1dLmNvbmNhdChpKX0se2NOOiJmdW5jdGlvbiIsYks6ImRlZiIsZToiJHw7IixjOltlLmluaGVyaXQoZS5UTSx7Yjp0fSksY10uY29uY2F0KGkpfSx7YjplLklSKyI6OiJ9LHtjTjoic3ltYm9sIixiOmUuVUlSKyIoXFwhfFxcPyk/OiIscjowfSx7Y046InN5bWJvbCIsYjoiOig/IVxccykiLGM6W3Mse2I6dH1dLHI6MH0se2NOOiJudW1iZXIiLGI6IihcXGIwWzAtN19dKyl8KFxcYjB4WzAtOWEtZkEtRl9dKyl8KFxcYlsxLTldWzAtOV9dKihcXC5bMC05X10rKT8pfFswX11cXGIiLHI6MH0se2I6IihcXCRcXFcpfCgoXFwkfFxcQFxcQD8pKFxcdyspKSJ9LHtjTjoicGFyYW1zIixiOi9cfC8sZTovXHwvLGs6cn0se2I6IigiK2UuUlNSKyJ8dW5sZXNzKVxccyoiLGs6InVubGVzcyIsYzpbbyx7Y046InJlZ2V4cCIsYzpbZS5CRSxuXSxpOi9cbi8sdjpbe2I6Ii8iLGU6Ii9bYS16XSoifSx7YjoiJXJ7IixlOiJ9W2Etel0qIn0se2I6IiVyXFwoIixlOiJcXClbYS16XSoifSx7YjoiJXIhIixlOiIhW2Etel0qIn0se2I6IiVyXFxbIixlOiJcXF1bYS16XSoifV19XS5jb25jYXQoaSkscjowfV0uY29uY2F0KGkpO24uYz1sO3ZhciBOPVt7YjovXlxzKj0+LyxzdGFydHM6e2U6IiQiLGM6Yy5jPWx9fSx7Y046Im1ldGEiLGI6Il4oWz4/XT58W1xcdyNdK1xcKFxcdytcXCk6XFxkKzpcXGQrPnwoXFx3Ky0pP1xcZCtcXC5cXGQrXFwuXFxkKHBcXGQrKT9bXj5dKz4pIixzdGFydHM6e2U6IiQiLGM6bH19XTtyZXR1cm57YWxpYXNlczpbInJiIiwiZ2Vtc3BlYyIsInBvZHNwZWMiLCJ0aG9yIiwiaXJiIl0sazpyLGk6L1wvXCovLGM6aS5jb25jYXQoTikuY29uY2F0KGwpfX0pLG8ucmVnaXN0ZXJMYW5ndWFnZSgieWFtbCIsZnVuY3Rpb24oZSl7dmFyIHQ9InRydWUgZmFsc2UgeWVzIG5vIG51bGwiLHI9Il5bIFxcLV0qIixhPSJbYS16QS1aX11bXFx3XFwtXSoiLG89e2NOOiJhdHRyIix2Olt7YjpyK2ErIjoifSx7YjpyKyciJythKyciOid9LHtiOnIrIiciK2ErIic6In1dfSxpPXtjTjoic3RyaW5nIixyOjAsdjpbe2I6LycvLGU6LycvfSx7YjovIi8sZTovIi99LHtiOi9cUysvfV0sYzpbZS5CRSx7Y046InRlbXBsYXRlLXZhcmlhYmxlIix2Olt7Yjoie3siLGU6In19In0se2I6IiV7IixlOiJ9In1dfV19O3JldHVybntjSTohMCxhbGlhc2VzOlsieW1sIiwiWUFNTCIsInlhbWwiXSxjOltvLHtjTjoibWV0YSIsYjoiXi0tLXMqJCIscjoxMH0se2NOOiJzdHJpbmciLGI6IltcXHw+XSAqJCIsckU6ITAsYzppLmMsZTpvLnZbMF0uYn0se2I6IjwlWyU9LV0/IixlOiJbJS1dPyU+IixzTDoicnVieSIsZUI6ITAsZUU6ITAscjowfSx7Y046InR5cGUiLGI6IiEiK2UuVUlSfSx7Y046InR5cGUiLGI6IiEhIitlLlVJUn0se2NOOiJtZXRhIixiOiImIitlLlVJUisiJCJ9LHtjTjoibWV0YSIsYjoiXFwqIitlLlVJUisiJCJ9LHtjTjoiYnVsbGV0IixiOiJeICotIixyOjB9LGUuSENNLHtiSzp0LGs6e2xpdGVyYWw6dH19LGUuQ05NLGldfX0pLG99KTs="></script>
  <script src="data:text/javascript;base64,dmFyIHRlID0gd2luZG93LnByZXZpZXdlciA9IHsNCiAgICBtbUVkaXRvcjogbnVsbCwNCiAgICBpc1ByZXZpZXdFZGl0b3JTeW5jOiBmYWxzZSwNCiAgICBjb2RlU2Nyb2xsZWQ6IG5ldyBEYXRlKCkuZ2V0VGltZSgpICsgMjUwMCwNCiAgICBoaWdobGlnaHRUaW1lb3V0OiAxODAwDQp9Ow0KdmFyIGlzRGVidWcgPSBmYWxzZTsNCg0KLy8gVGhpcyBmdW5jdGlvbiBpcyBnbG9iYWwgYW5kIGNhbGxlZCBieSB0aGUgcGFyZW50DQovLyB0byBwYXNzIGluIHRoZSBmb3JtIG9iamVjdCBhbmQgcGFzcyBiYWNrIHRoZSB0ZXh0DQovLyBlZGl0b3IgaW5zdGFuY2UgdGhhdCBhbGxvd3MgdGhlIHBhcmVudCB0byBtYWtlDQovLyBjYWxscyBpbnRvIHRoaXMgY29tcG9uZW50DQpmdW5jdGlvbiBpbml0aWFsaXplaW50ZXJvcChlZGl0b3IpIHsNCiAgICBpZiAod2luZG93LmRvdG5ldFByb3h5KSB7DQogICAgICAgIHRlLm1tRWRpdG9yID0gd2luZG93LmRvdG5ldFByb3h5Ow0KICAgIH0gZWxzZQ0KICAgICAgICB0ZS5tbUVkaXRvciA9IGVkaXRvcjsNCg0KICAgIHRlLmlzUHJldmlld0VkaXRvclN5bmMgPSB0ZS5tbUVkaXRvci5pc1ByZXZpZXdUb0VkaXRvclN5bmMoKTsNCiAgICBzY3JvbGwoKTsNCg0KfQ0KDQokKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbigpIHsNCiAgICBoaWdobGlnaHRDb2RlKCk7DQoNCiAgICAvLyBuYXZpZ2F0ZSBhbGwgbGlua3MgZXh0ZXJuYWxseSBpbiBkZWZhdWx0IGJyb3dzZXINCiAgICAkKGRvY3VtZW50KS5vbigiY2xpY2siLA0KICAgICAgICAiYSIsDQogICAgICAgIGZ1bmN0aW9uKGUpIHsNCiAgICAgICAgICAgIHZhciB1cmwgPSB0aGlzLmhyZWY7DQogICAgICAgICAgICB2YXIgcmF3SHJlZiA9ICQodGhpcykuYXR0cigiaHJlZiIpOw0KICAgICAgICAgICAgdmFyIGhhc2ggPSB0aGlzLmhhc2g7DQoNCiAgICAgICAgICAgIC8vIE5vdGlmeSBvZiBsaW5rIG5hdmlnYXRpb24gYW5kIGhhbmRsZSBleHRlcm5hbCB1cmxzDQogICAgICAgICAgICAvLyBpZiBub3QgaGFuZGxlZCBlbHNld2hlcmUNCiAgICAgICAgICAgIGlmICh0ZS5tbUVkaXRvciAmJiB0ZS5tbUVkaXRvci5QcmV2aWV3TGlua05hdmlnYXRpb24odXJsLCByYXdIcmVmKSkgew0KICAgICAgICAgICAgICAgIC8vIGl0IHRydWUgZWRpdG9yIGhhbmRsZWQgdGhlIG5hdmlnYXRpb24NCiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7DQogICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlOw0KICAgICAgICAgICAgfQ0KDQogICAgICAgICAgICBpZiAoaGFzaCkgew0KICAgICAgICAgICAgICAgIGhhc2ggPSBkZWNvZGVVUklDb21wb25lbnQoaGFzaCk7DQogICAgICAgICAgICAgICAgdmFyIHNlbCA9ICJhW25hbWU9JyIgKyBoYXNoLnN1YnN0cigxKSArICInXSwjIiArIGhhc2guc3Vic3RyKDEpOw0KICAgICAgICAgICAgICAgIHZhciAkZWwgPSAkKHNlbCk7DQogICAgICAgICAgICAgICAgJCgiaHRtbCIpLnNjcm9sbFRvcCgkZWwub2Zmc2V0KCkudG9wIC0gMTAwKTsNCiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7DQogICAgICAgICAgICB9DQogICAgICAgIH0pOw0KICAgIC8vIGRlZmluaXRpb24gbGlzdHMNCiAgICAkKGRvY3VtZW50KS5vbigiY2xpY2siLA0KICAgICAgICAiZHQiLA0KICAgICAgICBmdW5jdGlvbigpIHsNCiAgICAgICAgICAgICQodGhpcykubmV4dFVudGlsKCJkdCIpLnRvZ2dsZSgpOw0KICAgICAgICB9KTsNCn0pOw0KDQokKGRvY3VtZW50KS5vbigiY29udGV4dG1lbnUiLA0KICAgIGZ1bmN0aW9uIChlKSB7DQogICAgICAgIHZhciBwYXJtID0geyBUb3A6IDEsIExlZnQ6IDEsIElkOiAnJywgVHlwZTogJycsIFNyYzonJywgSHJlZjogJycgfTsNCg0KICAgICAgICBpZiAoZS50YXJnZXQpIHsNCiAgICAgICAgICAgIHBhcm0uSWQgPSBlLnRhcmdldC5pZDsNCiAgICAgICAgICAgIHBhcm0uVHlwZSA9IGUudGFyZ2V0Lm5vZGVOYW1lOw0KDQogICAgICAgICAgICBpZiAoZS50YXJnZXQuc3JjKQ0KICAgICAgICAgICAgICAgIHBhcm0uU3JjID0gZS50YXJnZXQuc3JjOw0KICAgICAgICAgICAgaWYgKGUudGFyZ2V0LmhyZWYpDQogICAgICAgICAgICAgICAgcGFybS5IcmVmID0gJChlLnRhcmdldCkuYXR0cigiaHJlZiIpOw0KICAgICAgICB9DQogICAgICAgIA0KICAgICAgICBpZiAodGUubW1FZGl0b3IpIHsNCiAgICAgICAgICAgIHRlLm1tRWRpdG9yLnByZXZpZXdDb250ZXh0TWVudShwYXJtKTsNCiAgICAgICAgICAgIHJldHVybiBmYWxzZTsNCiAgICAgICAgfQ0KICAgICAgICByZXR1cm4gdHJ1ZTsNCiAgICAgICAgLy8gaW5zaWRlIG9mIFdlYkJyb3dzZXIgY29udHJvbCBkb24ndCBzaG93IGNvbnRleHQgbWVudQ0KICAgICAgICAvL3JldHVybiBuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoIlRyaWRlbnQiKSA+IC0xID8gZmFsc2UgOiB0cnVlOw0KICAgIH0pOw0KDQp3aW5kb3cub25kcm9wID0gZnVuY3Rpb24gKGV2ZW50KSB7DQogICAgLy8gZG9uJ3QgYWxsb3cgZHJvcHBpbmcgaGVyZSAtIHdlIGNhbid0IGdldCBmdWxsIGZpbGUgaW5mbw0KICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7DQogICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7DQoNCiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsNCiAgICAgICAgYWxlcnQoIlRvIG9wZW4gZHJvcHBlZCBmaWxlcyBpbiBNYXJrZG93biBNb25zdGVyLCBwbGVhc2UgZHJvcCBmaWxlcyBvbnRvIHRoZSBoZWFkZXIgYXJlYSBvZiB0aGUgd2luZG93LiIpOw0KICAgIH0sIDUwKTsNCn0NCg0Kd2luZG93Lm9uZHJhZ292ZXIgPSBmdW5jdGlvbiAoZXZlbnQpIHsNCiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpOw0KICAgIHJldHVybiBmYWxzZTsNCn0NCg0KLy8gc2Nyb2xsIGVkaXRvciB0byB0aGUgc2Nyb2xsIHBvc2l0aW9uIG9mIHRoZSBwcmV2aWV3DQp2YXIgc2Nyb2xsID0gZGVib3VuY2UoZnVuY3Rpb24gKGV2ZW50KSB7DQoNCiAgICBpZiAoIXRlLm1tRWRpdG9yIHx8ICF0ZS5pc1ByZXZpZXdFZGl0b3JTeW5jKSByZXR1cm47DQoNCiAgICAvLyBwcmV2ZW50IHJlcG9zaXRpb25pbmcgZWRpdG9yIHNjcm9sbCBzeW5jDQogICAgLy8gd2hlbiBzZWxlY3RpbmcgbGluZSBpbiBlZGl0b3IgKHcvIHR3byB3YXkgc3luYykNCiAgICAvLyB0ZS5jb2RlU2Nyb2xsZWQgaXMgc2V0IGluIHNjcm9sbFRvUHJhZ21hTGluZXMgc28gdGhhdCB3ZSBkb24ndA0KICAgIC8vIHJlLW5hdmlnYXRlDQogICAgdmFyIHQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTsNCiAgICBpZiAodGUuY29kZVNjcm9sbGVkID4gdCAtIDI3MCkgDQogICAgICByZXR1cm47DQogICAgDQogICAgdmFyIHN0ID0gd2luZG93LmRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxUb3A7DQogICAgdmFyIHNoID0gd2luZG93LmRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxIZWlnaHQgLSB3aW5kb3cuZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDsNCg0KICAgIA0KICAgIGlmIChzdCA8IDMpIHsNCiAgICAgIHRlLm1tRWRpdG9yLmdvdG9MaW5lKDAsIHRydWUpOw0KICAgICAgICByZXR1cm47DQogICAgfQ0KICAgIC8vIGlmIHdlJ3JlIG9uIHRoZSBsYXN0IHBhZ2UNCiAgICBpZiAoc2ggPT09IHN0KSB7DQogICAgICBjb25zb2xlLmxvZygiR29pbmcgdG8gYm90dG9tIG9mIEVkaXRvciIpOw0KICAgICAgLy90ZS5tbUVkaXRvci5nb3RvTGluZSg5OTk5OTk5LCB0cnVlLCB0cnVlKTsNCiAgICAgIHRlLm1tRWRpdG9yLmdvdG9Cb3R0b20odHJ1ZSwgdHJ1ZSk7DQogICAgICByZXR1cm47DQogICAgfQ0KDQogICAgdmFyIHdpblRvcCA9IHN0ICsgMTAwOw0KDQoNCiAgICB2YXIgJGxpbmVzID0gJCgiW2lkKj0ncHJhZ21hLWxpbmUtJ10iKTsNCg0KICAgIGlmICgkbGluZXMubGVuZ3RoIDwgMSkNCiAgICAgICAgcmV0dXJuOw0KDQogICAgdmFyIGlkID0gbnVsbDsNCiAgICBmb3IgKHZhciBpID0gMDsgaSA8ICRsaW5lcy5sZW5ndGg7IGkrKykgew0KDQogICAgICAgIGlmICgkKCRsaW5lc1tpXSkucG9zaXRpb24oKS50b3AgPj0gd2luVG9wKSB7DQogICAgICAgICAgICBpZCA9ICRsaW5lc1tpXS5pZDsNCiAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICB9DQogICAgfQ0KICAgIGlmICghaWQpDQogICAgICAgIHJldHVybjsNCg0KICAgIGlkID0gaWQucmVwbGFjZSgicHJhZ21hLWxpbmUtIiwgIiIpOw0KDQogICAgdmFyIGxpbmUgPSAoaWQgKiAxKSAtIDQ7DQogICAgdGUubW1FZGl0b3IuZ290b0xpbmUobGluZSwgdHJ1ZSk7DQp9LDUwKTsNCndpbmRvdy5vbnNjcm9sbCA9IHNjcm9sbDsNCg0KZnVuY3Rpb24gaGlnaGxpZ2h0Q29kZShsaW5lbm8pIHsNCg0KICAgIHZhciBwcmVzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgicHJlPmNvZGUiKTsNCg0KICAgIC8vIFRyeSB0byBmaW5kIGxpbmVubyBpbiBkb2MgLSBpZiBsaW5lbm8gaXMgcGFzc2VkDQogICAgLy8gYW5kIHJlbmRlciBvbmx5IHRob3NlIHBsdXMgcGFkZGluZyBhYm92ZSBhbmQgYmVsb3cNCiAgICB2YXIgbGluZVBvcyA9IDA7DQogICAgaWYgKGxpbmVubyAmJiBwcmVzLmxlbmd0aCA+IDIwMCkgew0KICAgICAgICB2YXIgJGVsID0gJCgiI3ByYWdtYS1saW5lLSIgKyBsaW5lbm8pOw0KICAgICAgICBpZiAoJGVsLmxlbmd0aCA8IDEpIHsNCiAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgMTA7IGorKykgew0KICAgICAgICAgICAgICAgIGlmIChsaW5lbm8gLSBqIDwgMCkNCiAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgdmFyICRlbCA9ICQoIiNwcmFnbWEtbGluZS0iICsgKGxpbmVubyAtIGopICk7DQogICAgICAgICAgICAgICAgaWYgKCRlbC5sZW5ndGggPiAwKQ0KICAgICAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGlmICgkZWwubGVuZ3RoIDwgMSkgew0KICAgICAgICAgICAgICAgIGZvciAodmFyIGsgPSAwOyBrIDwgMTA7IGsrKykgew0KICAgICAgICAgICAgICAgICAgICB2YXIgJGVsID0gJCgiI3ByYWdtYS1saW5lLSIgKyAobGluZW5vICsgaykgKTsNCiAgICAgICAgICAgICAgICAgICAgaWYgKCRlbC5sZW5ndGggPiAwKQ0KICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQogICAgICAgIGlmICgkZWwubGVuZ3RoID4gMCkgew0KICAgICAgICAgICAgbGluZVBvcyA9ICRlbC5wb3NpdGlvbigpLnRvcDsNCiAgICAgICAgfQ0KICAgIH0NCiAgICAvL2NvbnNvbGUubG9nKCJMaW5lIFBvczoiICsgbGluZVBvcyArICIgIiArIGxpbmVubyArICIgIiArICRlbCk7DQoNCiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHByZXMubGVuZ3RoOyBpKyspIHsNCiAgICAgICAgdmFyIGJsb2NrID0gcHJlc1tpXTsNCiAgICAgICAgdmFyICRjb2RlID0gJChibG9jayk7DQoNCiAgICAgICAgLy8gdG9vIG1hbnkgY29kZSBibG9ja3MgdG8gcmVuZGVyIG9yIHRleHQvcGxhaW4gc3R5bGVzIC0ganVzdCBzdHlsZQ0KICAgICAgICBpZiAoKHByZXMubGVuZ3RoID4gNDAwKSB8fA0KICAgICAgICAgICAgJGNvZGUuaGFzQ2xhc3MoImxhbmd1YWdlLXRleHQiKSB8fA0KICAgICAgICAgICAgJGNvZGUuaGFzQ2xhc3MoImxhbmd1YWdlLXBsYWluIikpIHsNCiAgICAgICAgICAgICAgICAkY29kZS5hZGRDbGFzcygiaGxqcyIpOw0KICAgICAgICAgICAgICAgIGNvbnRpbnVlOw0KICAgICAgICB9DQoNCiAgICAgICAgLy8gcmVuZGVyIG9ubHkgbWF0Y2hlZCBsaW5lcyB0aGF0IGFyZSBpbiB2aWV3cG9ydCArIHBhZGRpbmcNCiAgICAgICAgaWYgKGxpbmVQb3MgPiAwKSB7DQogICAgICAgICAgICB2YXIgdG9wID0gJGNvZGUucG9zaXRpb24oKS50b3A7DQoNCiAgICAgICAgICAgIGlmICh0b3AgPCBsaW5lUG9zIC0gMjAwMCkgew0KICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coIlNraXBwaW5nIHNtYWxsZXI6ICIgKyB0b3AsIGxpbmVQb3MpOw0KICAgICAgICAgICAgICAgIC8vJGNvZGUuYWRkQ2xhc3MoImhsanMiKTsNCiAgICAgICAgICAgICAgICBjb250aW51ZTsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICAgIGlmICh0b3AgPiBsaW5lUG9zICsgMjAwMCkgew0KICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coIkJyZWFraW5nIGxhcmdlcjogIiArIHRvcCwgbGluZVBvcyk7DQogICAgICAgICAgICAgICAgLy8kY29kZS5hZGRDbGFzcygiaGxqcyIpOw0KICAgICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgICAgfQ0KICAgICAgICB9DQoNCiAgICAgICAgaGxqcy5oaWdobGlnaHRCbG9jayhibG9jayk7DQoNCiAgICAgICAgLy8gVGhpcyBpcyBiZXR0ZXIgZm9yIHBlcmYgYnV0IG1ha2VzIHRoZSBwcmV2aWV3IGp1bXB5DQogICAgICAgIC8vc2V0VGltZW91dChmdW5jdGlvbihibCkgew0KICAgICAgICAvLyAgICBobGpzLmhpZ2hsaWdodEJsb2NrKGJsKTsNCiAgICAgICAgLy99LmJpbmQodGhpcywgYmxvY2spKTsNCiAgICB9DQoNCiAgICAvLyBhZGQgdGhlIGNvZGUgc25pcHBldCBzeW50YXggYW5kIGNvZGUgY29weWluZw0KDQogICAgaWYgKHdpbmRvdy5oaWdobGlnaHRKc0JhZGdlKQ0KICAgICAgICB3aW5kb3cuaGlnaGxpZ2h0SnNCYWRnZSgpOw0KfQ0KDQovLyB0aGlzIHdvcmtzLCBidXQgYXN5bmMgdXBkYXRlcyBvZiBjb2RlIGJsb2NrcyBpcyB0b28ganVtcHkNCi8vZnVuY3Rpb24gaGlnaGxpZ2h0Q29kZVdlYldvcmtlcigpIHsNCi8vICAgIHZhciBzY3JpcHQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgiUHJldmlld1NjcmlwdCIpOw0KDQovLyAgICBpZiAoIXNjcmlwdCkgew0KLy8gICAgICAgIGFsZXJ0KCdQUmV2aWV3U2NyaXB0IHRhZyBub3QgZm91bmQnKTsNCi8vICAgICAgICByZXR1cm47DQovLyAgICB9DQoNCi8vICAgIHNjcmlwdCA9IHNjcmlwdC5zcmMucmVwbGFjZSgiL3ByZXZpZXcuanMiLCAiL2hpZ2hsaWdodEpzV29ya2VyLmpzIik7DQovLyAgICBjb25zb2xlLmxvZyhzY3JpcHQpOw0KDQoNCi8vICAgICQoInByZSBjb2RlIikNCi8vICAgICAgICAuZWFjaChmdW5jdGlvbiAoaSwgYmxvY2spIHsNCi8vICAgICAgICAgICAgdmFyICRibG9jayA9ICQoYmxvY2spOw0KLy8gICAgICAgICAgICB2YXIgY29kZSA9ICRibG9jay50ZXh0KCkudHJpbUVuZCgpOw0KDQovLyAgICAgICAgICAgIGNvbnNvbGUubG9nKCJ3b3JrZXIgbG9hZGVkIiwgd29ya2VyKTsNCg0KLy8gICAgICAgICAgICB2YXIgd29ya2VyID0gbmV3IFdvcmtlcihzY3JpcHQpOw0KLy8gICAgICAgICAgICB3b3JrZXIub25tZXNzYWdlID0gZnVuY3Rpb24gKGV2ZW50KSB7DQovLyAgICAgICAgICAgICAgICB2YXIgcmVzdWx0ID0gZXZlbnQuZGF0YTsNCi8vICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCJSZXN1bHQ6ICIsIHJlc3VsdC52YWx1ZSk7DQovLyAgICAgICAgICAgICAgICAkYmxvY2tbMF0ub3V0ZXJIVE1MID0NCi8vICAgICAgICAgICAgICAgICAgICAnPGNvZGUgY2xhc3M9Imxhbmd1YWdlLWphdmFzY3JpcHQiIGlkPSJwcmFnbWEtbGluZS04Ij4nICsgcmVzdWx0LnZhbHVlICsgJzwvY29kZT4nOyAvL2h0bWwoIHJlc3VsdC52YWx1ZSApOw0KDQovLyAgICAgICAgICAgICAgICB3b3JrZXIudGVybWluYXRlKCk7DQovLyAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygiZG9uZSBpbiB3ZWIgd29ya2VyIHJlc3BvbnNlIik7DQovLyAgICAgICAgICAgIH07DQovLyAgICAgICAgICAgIHZhciBsYW5nID0gJGJsb2NrLmF0dHIoImNsYXNzIik7DQovLyAgICAgICAgICAgIGlmIChsYW5nKQ0KLy8gICAgICAgICAgICAgICAgbGFuZyA9IGxhbmcucmVwbGFjZSgibGFuZ3VhZ2UtIiwgIiIpOw0KDQovLyAgICAgICAgICAgIHZhciBkID0gew0KLy8gICAgICAgICAgICAgICAgY29kZTogY29kZSwNCi8vICAgICAgICAgICAgICAgIGxhbmc6IGxhbmcsDQovLyAgICAgICAgICAgICAgICBzY3JpcHQ6IHNjcmlwdC5yZXBsYWNlKCIvaGlnaGxpZ2h0SnNXb3JrZXIuanMiLCAiL2hpZ2hsaWdodGpzL2hpZ2hsaWdodC5wYWNrLmpzIikNCi8vICAgICAgICAgICAgfTsNCi8vICAgICAgICAgICAgd29ya2VyLnBvc3RNZXNzYWdlKGQpOw0KLy8gICAgICAgICAgICBjb25zb2xlLmxvZygiUG9zdE1lc3NhZ2UgY2FsbGVkIiwgZCk7DQovLyAgICAgICAgfSk7DQovL30NCg0KZnVuY3Rpb24gdXBkYXRlRG9jdW1lbnRDb250ZW50KGh0bWwsIGxpbmVubykgew0KICAvL2NvbnNvbGUubG9nKCd1cGRhdGUgZG9jdW1lbnQgY29udGVudCcpOw0KICB0ZS5pc1ByZXZpZXdFZGl0b3JTeW5jID0gdGUubW1FZGl0b3IuaXNQcmV2aWV3VG9FZGl0b3JTeW5jKCk7DQogIC8vIGNvbnNvbGUubG9nKCJBc3NpZ25pbmcgaHRtbCBiZWZvcmUgVGltZW91dCAiICsgbmV3IERhdGUoKS5nZXRUaW1lKCkpOw0KDQogIHZhciBlbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJNYWluQ29udGVudCIpOw0KICBpZiAoIWVsKQ0KICAgIHJldHVybjsNCiAgZWwuaW5uZXJIVE1MID0gaHRtbDsNCg0KICBoaWdobGlnaHRDb2RlKGxpbmVubyk7DQoNCiAgLy8gUmFpc2UgYSBwcmV2aWV3VXBkYXRlZCBldmVudCBvbiB0aGUgZG9jdW1lbnQNCiAgdmFyIGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoIkV2ZW50Iik7DQogIGV2ZW50LmluaXRFdmVudCgicHJldmlld1VwZGF0ZWQiLCBmYWxzZSwgdHJ1ZSk7DQoNCiAgZXZlbnQudGFyZ2V0ID0gZWw7DQogIGV2ZW50LmN1cnJlbnRUYXJnZXQgPSBlbDsNCiAgZG9jdW1lbnQuZGlzcGF0Y2hFdmVudChldmVudCk7DQp9DQoNCmZ1bmN0aW9uIHNjcm9sbFRvUHJhZ21hTGluZShsaW5lbm8sIGhlYWRlcklkKSB7DQogIGlmICh0eXBlb2YgbGluZW5vICE9PSAibnVtYmVyIiB8fCBsaW5lbm8gPCAwKSByZXR1cm47DQoNCiAgICBjb25zb2xlLmxvZygiU2Nyb2xsVG9QcmFnbWFMaW5lOiAiICsgbGluZW5vKTsNCg0KICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgew0KICAgIHRyeSB7DQogICAgICB2YXIgJGVsOw0KICAgICAgICBpZiAoaGVhZGVySWQgIT0gbnVsbCkNCiAgICAgICAgICAkZWwgPSAkKCIjIiArIGhlYWRlcklkKTsNCiAgICAgICAgaWYgKCRlbC5sZW5ndGggPCAxKQ0KICAgICAgICAgICRlbCA9ICQoIiNwcmFnbWEtbGluZS0iICsgbGluZW5vKTsNCg0KICAgICAgICBpZiAoJGVsLmxlbmd0aCA8IDEpIHsNCiAgICAgICAgICB2YXIgb3JpZ0xpbmUgPSBsaW5lbm87DQoNCiAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IDM7IGkrKykgew0KICAgICAgICAgICAgbGluZW5vLS07DQogICAgICAgICAgICAkZWwgPSAkKCIjcHJhZ21hLWxpbmUtIiArIGxpbmVubyk7DQogICAgICAgICAgICBpZiAoJGVsLmxlbmd0aCA+IDApDQogICAgICAgICAgICAgIGJyZWFrOw0KICAgICAgICAgIH0NCg0KDQogICAgICAgICAgLy8gdHJ5IGJhY2t3YXJkcyB3aXRoIDMgbGluZXMNCiAgICAgICAgICBpZiAoJGVsLmxlbmd0aCA8IDEpIHsNCiAgICAgICAgICAgIGxpbmVubyA9IG9yaWdMaW5lOw0KDQogICAgICAgICAgICAvLyB0cnkgZm9yd2FyZCB3aXRoIDMgbGluZXMNCiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMzsgaSsrKSB7DQogICAgICAgICAgICAgIGxpbmVubysrOw0KICAgICAgICAgICAgICAkZWwgPSAkKCIjcHJhZ21hLWxpbmUtIiArIGxpbmVubyk7DQogICAgICAgICAgICAgIGlmICgkZWwubGVuZ3RoID4gMCkNCiAgICAgICAgICAgICAgICBicmVhazsNCiAgICAgICAgICAgIH0NCiAgICAgICAgICB9DQogICAgICAgICAgaWYgKCRlbC5sZW5ndGggPCAxKQ0KICAgICAgICAgICAgcmV0dXJuOw0KICAgICAgICB9DQoNCiAgICAgICAgJGVsLmFkZENsYXNzKCJsaW5lLWhpZ2hsaWdodCIpOw0KICAgICAgICBpZiAodGUuaGlnaGxpZ2h0VGltZW91dCA+IDApDQogICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHsgJGVsLnJlbW92ZUNsYXNzKCJsaW5lLWhpZ2hsaWdodCIpOyB9LCB0ZS5oaWdobGlnaHRUaW1lb3V0KTsNCg0KICAgICAgICB0ZS5jb2RlU2Nyb2xsZWQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTsgLy8gZG9uJ3Qgc2Nyb2xsIGVkaXRvciBvbmNlIHdlIG1vdmUNCiAgICAgICAgaWYgKGxpbmVubyA8IDIpIA0KICAgICAgICAgICQoImh0bWwiKS5zY3JvbGxUb3AoMCk7DQogICAgICAgIGVsc2UNCiAgICAgICAgICAkKCJodG1sIikuc2Nyb2xsVG9wKCRlbC5vZmZzZXQoKS50b3AgLSAyNSk7IC8vIC0xNTANCiAgICB9IGNhdGNoIChleCkgeyB9DQogICAgICANCiAgICB9LDIwKTsNCn0NCg0KZnVuY3Rpb24gZ2V0U2Nyb2xsVG9wKCkgew0KDQogICAgdmFyIHN0ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcDsNCiAgICBpZiAoIXN0KQ0KICAgICAgICByZXR1cm4gMDsNCiAgICByZXR1cm4gc3Q7DQp9DQoNCmZ1bmN0aW9uIHN0YXR1cyhtc2csYXBwZW5kKSB7DQogICAgdmFyICRlbCA9ICQoIiNzdGF0dXNtZXNzYWdlIik7DQogICAgaWYgKCRlbC5sZW5ndGggPCAxKSB7DQogICAgICAgICRlbCA9ICQoIjxkaXYgaWQ9J3N0YXR1c21lc3NhZ2UnIHN0eWxlPSdwb3NpdGlvbjogZml4ZWQ7IG9wYWNpdHk6IDAuODsgbGVmdDowOyByaWdodDowOyBib3R0b206IDA7IHBhZGRpbmc6IDVweCAxMHB4OyBiYWNrZ3JvdW5kOiAjNDQ0OyBjb2xvcjogd2hpdGU7Jz48L2Rpdj4iKTsNCiAgICAgICAgJChkb2N1bWVudC5ib2R5KS5hcHBlbmQoJGVsKTsNCiAgICB9DQoNCiAgICBpZiAoYXBwZW5kKSB7DQogICAgICAgIHZhciBodG1sID0gJGVsLmh0bWwoKSArDQogICAgICAgICAgICAiPGJyLz4iICsNCiAgICAgICAgICAgIG1zZzsNCiAgICAgICAgJGVsLmh0bWwoaHRtbCk7DQogICAgfQ0KICAgIGVsc2UNCiAgICAgICAgJGVsLnRleHQobXNnKTsNCg0KICAgICRlbC5zaG93KCk7DQogICAgc2V0VGltZW91dChmdW5jdGlvbigpIHsgJGVsLnRleHQoIiIpOyAkZWwuZmFkZU91dCgpIH0sIDYwMDApOw0KfQ0KDQoNCndpbmRvdy5vbmVycm9yID0gZnVuY3Rpb24gd2luZG93RXJyb3IobWVzc2FnZSwgZmlsZW5hbWUsIGxpbmVubywgY29sbm8sIGVycm9yKSB7DQogICAgaWYgKCFpc0RlYnVnKQ0KICAgICAgICByZXR1cm4gdHJ1ZTsNCg0KICAgIHZhciBtc2cgPSAiIjsNCiAgICBpZiAobWVzc2FnZSkNCiAgICAgICAgbXNnID0gbWVzc2FnZTsNCiAgICAvL2lmIChmaWxlbmFtZSkNCiAgICAvLyAgICBtc2cgKz0gIiwgIiArIGZpbGVuYW1lOw0KICAgIGlmIChsaW5lbm8pDQogICAgICAgIG1zZyArPSAiICgiICsgbGluZW5vICsgIiwiICsgY29sbm8gKyAiKSI7DQogICAgaWYgKGVycm9yKQ0KICAgICAgICBtc2cgKz0gZXJyb3I7DQoNCiAgICAvLyBzaG93IGVycm9yIG1lc3NhZ2VzIGluIGEgbGl0dGxlIHBvcCBvdmVyd2luZG93DQogICAgaWYgKGlzRGVidWcpDQogICAgICAgIHN0YXR1cyhtc2cpOw0KDQogICAgY29uc29sZS5sb2coIkVycm9yOiAiICsgbXNnKTsNCg0KICAgIC8vIGRvbid0IGxldCBlcnJvcnMgdHJpZ2dlciBicm93c2VyIHdpbmRvdw0KICAgIHJldHVybiB0cnVlOw0KfQ0KDQpmdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0LCBpbW1lZGlhdGUpIHsNCiAgICB2YXIgdGltZW91dDsNCiAgICByZXR1cm4gZnVuY3Rpb24gKCkgew0KICAgICAgICB2YXIgY29udGV4dCA9IHRoaXMsIGFyZ3MgPSBhcmd1bWVudHM7DQogICAgICAgIHZhciBsYXRlciA9IGZ1bmN0aW9uICgpIHsNCiAgICAgICAgICAgIHRpbWVvdXQgPSBudWxsOw0KICAgICAgICAgICAgaWYgKCFpbW1lZGlhdGUpIGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7DQogICAgICAgIH07DQogICAgICAgIHZhciBjYWxsTm93ID0gaW1tZWRpYXRlICYmICF0aW1lb3V0Ow0KICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7DQogICAgICAgIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGxhdGVyLCB3YWl0KTsNCiAgICAgICAgaWYgKGNhbGxOb3cpDQogICAgICAgICAgICBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpOw0KICAgIH07DQp9Ow0KDQoNCg0KLyogRVM1IFBPTFlGSUxMUyAqLw0KDQovLyBTdHJpbmcudHJpbSgpIGZvciBFUzUgcG9seWZpbGwNCmlmICghU3RyaW5nLnByb3RvdHlwZS50cmltKSB7DQogICAgU3RyaW5nLnByb3RvdHlwZS50cmltID0gZnVuY3Rpb24gKCkgew0KICAgICAgICByZXR1cm4gdGhpcy5yZXBsYWNlKC9eW1xzXHVGRUZGXHhBMF0rfFtcc1x1RkVGRlx4QTBdKyQvZywgJycpOw0KICAgIH07DQp9DQoNCmlmICghU3RyaW5nLnByb3RvdHlwZS50cmltRW5kKSB7DQogICAgU3RyaW5nLnByb3RvdHlwZS50cmltRW5kID0gZnVuY3Rpb24gKGMpIHsNCiAgICAgICAgaWYgKGMpDQogICAgICAgICAgICByZXR1cm4gdGhpcy5yZXBsYWNlKG5ldyBSZWdFeHAoYy5lc2NhcGVSZWdFeHAoKSArICIqJCIpLCAnJyk7DQogICAgICAgIHJldHVybiB0aGlzLnJlcGxhY2UoL1xzKyQvLCAnJyk7DQogICAgfTsNCn0NCg0KaWYgKCFTdHJpbmcucHJvdG90eXBlLnN0YXJ0c1dpdGgpIHsNCiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoU3RyaW5nLnByb3RvdHlwZSwgJ3N0YXJ0c1dpdGgnLCB7DQogICAgICAgIHZhbHVlOiBmdW5jdGlvbiAoc2VhcmNoLCByYXdQb3MpIHsNCiAgICAgICAgICAgIHBvcyA9IHJhd1BvcyA+IDAgPyByYXdQb3MgfCAwIDogMDsNCiAgICAgICAgICAgIHJldHVybiB0aGlzLnN1YnN0cmluZyhwb3MsIHBvcyArIHNlYXJjaC5sZW5ndGgpID09PSBzZWFyY2g7DQogICAgICAgIH0NCiAgICB9KTsNCn0NCg0KLy8gT2JqZWN0LmFzc2lnbigpIGZvciBFUzUgcG9seWZpbGwNCmlmICh0eXBlb2YgT2JqZWN0LmFzc2lnbiAhPT0gJ2Z1bmN0aW9uJykgew0KICAgIC8vIE11c3QgYmUgd3JpdGFibGU6IHRydWUsIGVudW1lcmFibGU6IGZhbHNlLCBjb25maWd1cmFibGU6IHRydWUNCiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoT2JqZWN0LCAiYXNzaWduIiwgew0KICAgICAgICB2YWx1ZTogZnVuY3Rpb24gYXNzaWduKHRhcmdldCwgdmFyQXJncykgeyAvLyAubGVuZ3RoIG9mIGZ1bmN0aW9uIGlzIDINCiAgICAgICAgICAgICd1c2Ugc3RyaWN0JzsNCiAgICAgICAgICAgIGlmICh0YXJnZXQgPT09IG51bGwgfHwgdGFyZ2V0ID09PSB1bmRlZmluZWQpIHsNCiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdDYW5ub3QgY29udmVydCB1bmRlZmluZWQgb3IgbnVsbCB0byBvYmplY3QnKTsNCiAgICAgICAgICAgIH0NCg0KICAgICAgICAgICAgdmFyIHRvID0gT2JqZWN0KHRhcmdldCk7DQoNCiAgICAgICAgICAgIGZvciAodmFyIGluZGV4ID0gMTsgaW5kZXggPCBhcmd1bWVudHMubGVuZ3RoOyBpbmRleCsrKSB7DQogICAgICAgICAgICAgICAgdmFyIG5leHRTb3VyY2UgPSBhcmd1bWVudHNbaW5kZXhdOw0KDQogICAgICAgICAgICAgICAgaWYgKG5leHRTb3VyY2UgIT09IG51bGwgJiYgbmV4dFNvdXJjZSAhPT0gdW5kZWZpbmVkKSB7DQogICAgICAgICAgICAgICAgICAgIGZvciAodmFyIG5leHRLZXkgaW4gbmV4dFNvdXJjZSkgew0KICAgICAgICAgICAgICAgICAgICAgICAgLy8gQXZvaWQgYnVncyB3aGVuIGhhc093blByb3BlcnR5IGlzIHNoYWRvd2VkDQogICAgICAgICAgICAgICAgICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG5leHRTb3VyY2UsIG5leHRLZXkpKSB7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9bbmV4dEtleV0gPSBuZXh0U291cmNlW25leHRLZXldOw0KICAgICAgICAgICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgICAgICAgICB9DQogICAgICAgICAgICAgICAgfQ0KICAgICAgICAgICAgfQ0KICAgICAgICAgICAgcmV0dXJuIHRvOw0KICAgICAgICB9LA0KICAgICAgICB3cml0YWJsZTogdHJ1ZSwNCiAgICAgICAgY29uZmlndXJhYmxlOiB0cnVlDQogICAgfSk7DQp9DQoNCg==" id="PreviewScript"></script>
  
</head>
<body>
<div id="MainContent">
    <!-- Markdown Monster Content -->
    <p><a href="https://royallib.com/read/gruber_martin/ponimanie_sql.html#0" target="_blank">https://royallib.com/read/gruber_martin/ponimanie_sql.html#0</a></p>
<!-- Start Document Outline -->
<ul>
<li><a href="#%D0%BF%D0%BE%D0%BD%D0%B8%D0%BC%D0%B0%D0%BD%D0%B8%D0%B5-sql">Понимание SQL</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-select">Команда SELECT</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B-update-insert-delete">Команды UPDATE, INSERT, DELETE</a>
<ul>
<li><a href="#update">UPDATE</a></li>
<li><a href="#insert">INSERT</a></li>
<li><a href="#delete">DELETE</a></li>
</ul>
</li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-create-table">Команда CREATE TABLE</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%B8%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B5">ПРЕДИСЛОВИЕ</a>
<ul>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-1-%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-%D1%80%D0%B5%D0%BB%D1%8F%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%83%D1%8E-%D0%B1%D0%B0%D0%B7%D1%83-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">Глава 1. ВВЕДЕНИЕ В РЕЛЯЦИОННУЮ БАЗУ ДАННЫХ</a>
<ul>
<li><a href="#%D1%81%D0%B2%D1%8F%D0%B7%D1%8B%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BE%D0%B4%D0%BD%D0%BE%D0%B9-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B-%D1%81-%D0%B4%D1%80%D1%83%D0%B3%D0%BE%D0%B9">СВЯЗЫВАНИЕ ОДНОЙ ТАБЛИЦЫ С ДРУГОЙ</a></li>
<li><a href="#%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA-%D1%81%D1%82%D1%80%D0%BE%D0%BA-%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%BB%D0%B5%D0%BD">ПОРЯДОК СТРОК ПРОИЗВОЛЕН</a></li>
<li><a href="#%D0%B8%D0%B4%D0%B5%D0%BD%D1%82%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D1%8F-%D1%81%D1%82%D1%80%D0%BE%D0%BA-%D0%BF%D0%B5%D1%80%D0%B2%D0%B8%D1%87%D0%BD%D1%8B%D0%B5-%D0%BA%D0%BB%D1%8E%D1%87%D0%B8-">ИДЕНТИФИКАЦИЯ СТРОК (ПЕРВИЧНЫЕ КЛЮЧИ )</a></li>
<li><a href="#%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D1%8B-%D0%B8%D0%BC%D0%B5%D0%BD%D1%83%D1%8E%D1%82%D1%81%D1%8F-%D0%B8-%D0%BD%D1%83%D0%BC%D0%B5%D1%80%D1%83%D1%8E%D1%82%D1%81%D1%8F">СТОЛБЦЫ ИМЕНУЮТСЯ И НУМЕРУЮТСЯ</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D0%BE%D0%B2%D0%B0%D1%8F-%D0%B1%D0%B0%D0%B7%D0%B0-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">ТИПОВАЯ БАЗА ДАННЫХ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5">РЕЗЮМЕ</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-2-sql--%D0%BE%D0%B1%D0%B7%D0%BE%D1%80">Глава 2. SQL : ОБЗОР.</a>
<ul>
<li><a href="#%D0%BA%D0%B0%D0%BA-%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82-sql">КАК РАБОТАЕТ SQL?</a></li>
<li><a href="#%D1%87%D1%82%D0%BE-%D0%B4%D0%B5%D0%BB%D0%B0%D0%B5%D1%82-ansi">ЧТО ДЕЛАЕТ ANSI?</a></li>
<li><a href="#%D0%B8%D0%BD%D1%82%D0%B5%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D1%8B%D0%B9-%D0%B8-%D0%B2%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9-sql">ИНТЕРАКТИВНЫЙ И ВЛОЖЕННЫЙ SQL</a></li>
<li><a href="#%D1%81%D1%83%D0%B1%D0%BF%D0%BE%D0%B4%D1%80%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-sql">СУБПОДРАЗДЕЛЕНИЯ SQL</a></li>
<li><a href="#%D1%80%D0%B0%D0%B7%D0%BB%D0%B8%D1%87%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">РАЗЛИЧНЫЕ ТИПЫ ДАННЫХ</a></li>
<li><a href="#sql-%D0%BD%D0%B5%D1%81%D0%BE%D0%B3%D0%BB%D0%B0%D1%81%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8">SQL НЕСОГЛАСОВАННОСТИ</a></li>
<li><a href="#%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5---%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C">ЧТО ТАКОЕ - ПОЛЬЗОВАТЕЛЬ?</a></li>
<li><a href="#%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D1%8F-%D0%B8-%D1%82%D0%B5%D1%80%D0%BC%D0%B8%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F">УСЛОВИЯ И ТЕРМИНОЛОГИЯ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-1">РЕЗЮМЕ</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-3-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-sql-%D0%B4%D0%BB%D1%8F-%D0%B8%D0%B7%D0%B2%D0%BB%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8%D0%BD%D1%84%D0%BE%D1%80%D0%BC%D0%B0%D1%86%D0%B8%D0%B8-%D0%B8%D0%B7-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86">Глава 3. ИСПОЛЬЗОВАНИЕ SQL ДЛЯ ИЗВЛЕЧЕНИЯ ИНФОРМАЦИИ ИЗ ТАБЛИЦ.</a>
<ul>
<li><a href="#%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">СОЗДАНИЕ ЗАПРОСА</a></li>
<li><a href="#%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81">ЧТО ТАКОЕ ЗАПРОС?</a></li>
<li><a href="#%D0%B3%D0%B4%D0%B5-%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D0%BD%D1%8F%D1%8E%D1%82%D1%81%D1%8F-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B">ГДЕ ПРИМЕНЯЮТСЯ ЗАПРОСЫ?</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-select-1">КОМАНДА SELECT</a></li>
<li><a href="#sql-execution-log">SQL Execution Log</a></li>
<li><a href="#%D0%B2%D1%8B%D0%B1%D0%B8%D1%80%D0%B0%D0%B9%D1%82%D0%B5-%D0%B2%D1%81%D0%B5%D0%B3%D0%B4%D0%B0-%D1%81%D0%B0%D0%BC%D1%8B%D0%B9-%D0%BF%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9-%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1">ВЫБИРАЙТЕ ВСЕГДА САМЫЙ ПРОСТОЙ СПОСОБ</a></li>
<li><a href="#%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5-select">ОПИСАНИЕ SELECT</a></li>
<li><a href="#%D0%BF%D1%80%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80-%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D0%BE%D0%B3%D0%BE-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%B0-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B">ПРОСМОТР ТОЛЬКО ОПРЕДЕЛЕННОГО СТОЛБЦА ТАБЛИЦЫ</a></li>
<li><a href="#%D0%BF%D0%B5%D1%80%D0%B5%D1%83%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%B0">ПЕРЕУПОРЯДОЧЕНИЕ СТОЛБЦА</a></li>
<li><a href="#%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D1%8B-distinct">ПАРАМЕТРЫ DISTINCT</a></li>
<li><a href="#distinct-%D0%B2%D0%BC%D0%B5%D1%81%D1%82%D0%BE-all">DISTINCT ВМЕСТО ALL</a></li>
<li><a href="#%D0%BA%D0%B2%D0%B0%D0%BB%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9-%D0%B2%D1%8B%D0%B1%D0%BE%D1%80-%D0%BF%D1%80%D0%B8-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B8-%D0%BF%D1%80%D0%B5%D0%B4%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9">КВАЛИФИЦИРОВАННЫЙ ВЫБОР ПРИ ИСПОЛЬЗОВАНИИ ПРЕДЛОЖЕНИЙ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-2">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-4-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%80%D0%B5%D0%BB%D1%8F%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D1%85-%D0%B8-%D0%B1%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D1%85-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BE%D0%B2-%D0%B4%D0%BB%D1%8F-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D1%8F-%D0%B1%D0%BE%D0%BB%D0%B5%D0%B5-%D0%B8%D0%B7%D0%BE%D1%89%D1%80%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%BF%D1%80%D0%B5%D0%B4%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D0%B2">Глава 4. ИСПОЛЬЗОВАНИЕ РЕЛЯЦИОННЫХ И БУЛЕВЫХ ОПЕРАТОРОВ ДЛЯ СОЗДАНИЯ БОЛЕЕ ИЗОЩРЕННЫХ ПРЕДИКАТОВ</a>
<ul>
<li><a href="#%D1%80%D0%B5%D0%BB%D1%8F%D1%86%D0%B8%D0%BE%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D1%8B">РЕЛЯЦИОННЫЕ ОПЕРАТОРЫ</a></li>
<li><a href="#%D0%B1%D1%83%D0%BB%D0%B5%D0%B2%D1%8B-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D1%8B">БУЛЕВЫ ОПЕРАТОРЫ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-3">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-1">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D0%BF%D0%B5%D1%86%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D1%85-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%BE%D0%B2-%D0%B2-%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D1%8F%D1%85">Глава 5. ИСПОЛЬЗОВАНИЕ СПЕЦИАЛЬНЫХ ОПЕРАТОРОВ В УСЛОВИЯХ</a>
<ul>
<li><a href="#%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80-in">ОПЕРАТОР IN</a></li>
<li><a href="#%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80-between">ОПЕРАТОР BETWEEN</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D1%8B%D0%BC%D0%B8-null--%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8">РАБОТА С НУЛЕВЫМИ( NULL ) ЗНАЧЕНИЯМИ</a></li>
<li><a href="#null-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80">NULL ОПЕРАТОР</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-not-%D1%81%D0%BE-%D1%81%D0%BF%D0%B5%D1%86%D0%B8%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC%D0%B8-%D0%BE%D0%BF%D0%B5%D1%80%D0%B0%D1%82%D0%BE%D1%80%D0%B0%D0%BC%D0%B8">ИСПОЛЬЗОВАНИЕ NOT СО СПЕЦИАЛЬНЫМИ ОПЕРАТОРАМИ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-4">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-2">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-6-%D0%BE%D0%B1%D0%BE%D0%B1%D1%89%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-%D0%B0%D0%B3%D1%80%D0%B5%D0%B3%D0%B0%D1%82%D0%BD%D1%8B%D1%85-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B9">Глава 6. ОБОБЩЕНИЕ ДАННЫХ С ПОМОЩЬЮ АГРЕГАТНЫХ ФУНКЦИЙ</a>
<ul>
<li><a href="#%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-%D0%B0%D0%B3%D1%80%D0%B5%D0%B3%D0%B0%D1%82%D0%BD%D1%8B%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">ЧТО ТАКОЕ АГРЕГАТНЫЕ ФУНКЦИИ?</a></li>
<li><a href="#%D0%BA%D0%B0%D0%BA-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D1%8C-%D0%B0%D0%B3%D1%80%D0%B5%D0%B3%D0%B0%D1%82%D0%BD%D1%8B%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">КАК ИСПОЛЬЗОВАТЬ АГРЕГАТНЫЕ ФУНКЦИИ?</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-count-%D1%81%D0%BE-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B0%D0%BC%D0%B8-%D0%B0-%D0%BD%D0%B5-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8">ИСПОЛЬЗОВАНИЕ COUNT СО СТРОКАМИ, А НЕ ЗНАЧЕНИЯМИ</a></li>
<li><a href="#%D0%B2%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B4%D1%83%D0%B1%D0%BB%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D0%B2-%D0%B2-%D0%B0%D0%B3%D1%80%D0%B5%D0%B3%D0%B0%D1%82%D0%BD%D1%8B%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">ВКЛЮЧЕНИЕ ДУБЛИКАТОВ В АГРЕГАТНЫЕ ФУНКЦИИ</a></li>
<li><a href="#%D0%B0%D0%B3%D1%80%D0%B5%D0%B3%D0%B0%D1%82%D1%8B-%D0%BF%D0%BE%D1%81%D1%82%D1%80%D0%BE%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BD%D0%B0-%D1%81%D0%BA%D0%B0%D0%BB%D1%8F%D1%80%D0%BD%D0%BE%D0%BC-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B8">АГРЕГАТЫ ПОСТРОЕННЫЕ НА СКАЛЯРНОМ ВЫРАЖЕНИИ</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-group-by">ПРЕДЛОЖЕНИЕ GROUP BY</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-having">ПРЕДЛОЖЕНИЕ HAVING</a></li>
<li><a href="#%D0%BD%D0%B5-%D0%B4%D0%B5%D0%BB%D0%B0%D0%B9%D1%82%D0%B5-%D0%B2%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%B0%D0%B3%D1%80%D0%B5%D0%B3%D0%B0%D1%82%D0%BE%D0%B2">НЕ ДЕЛАЙТЕ ВЛОЖЕННЫХ АГРЕГАТОВ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-5">РЕЗЮМЕ</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-7-%D1%84%D0%BE%D1%80%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B2%D1%8B%D0%B2%D0%BE%D0%B4%D0%BE%D0%B2-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2">Глава 7. ФОРМИРОВАНИЕ ВЫВОДОВ ЗАПРОСОВ</a>
<ul>
<li><a href="#%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8-%D0%B8-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F">СТРОКИ И ВЫРАЖЕНИЯ</a></li>
<li><a href="#%D1%81%D0%BA%D0%B0%D0%BB%D1%8F%D1%80%D0%BD%D0%BE%D0%B5-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-%D0%B2%D1%8B%D0%B1%D1%80%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9">СКАЛЯРНОЕ ВЫРАЖЕНИЕ С ПОМОЩЬЮ ВЫБРАННЫХ ПОЛЕЙ</a></li>
<li><a href="#%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D1%8B-%D0%B2%D1%8B%D0%B2%D0%BE%D0%B4%D0%B0">СТОЛБЦЫ ВЫВОДА</a></li>
<li><a href="#%D0%BF%D0%BE%D0%BC%D0%B5%D1%89%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%B0-%D0%B2-%D0%B2%D0%B0%D1%88%D0%B5%D0%BC-%D0%B2%D1%8B%D0%B2%D0%BE%D0%B4%D0%B5-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">ПОМЕЩЕНИЕ ТЕКСТА В ВАШЕМ ВЫВОДЕ ЗАПРОСА</a></li>
<li><a href="#%D1%83%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2%D1%8B%D0%B2%D0%BE%D0%B4%D0%B0-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9">УПОРЯДОЧЕНИЕ ВЫВОДА ПОЛЕЙ</a></li>
<li><a href="#%D1%83%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B0%D0%B3%D1%80%D0%B5%D0%B3%D0%B0%D1%82%D0%BD%D1%8B%D1%85-%D0%B3%D1%80%D1%83%D0%BF%D0%BF">УПОРЯДОЧЕНИЕ АГРЕГАТНЫХ ГРУПП</a></li>
<li><a href="#%D1%83%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2%D1%8B%D0%B2%D0%BE%D0%B4%D0%B0-%D0%BF%D0%BE-%D0%BD%D0%BE%D0%BC%D0%B5%D1%80%D1%83-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%B0">УПОРЯДОЧЕНИЕ ВЫВОДА ПО НОМЕРУ СТОЛБЦА</a></li>
<li><a href="#%D1%83%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-%D0%BE%D0%BF%D1%80%D0%B5%D1%82%D0%BE%D1%80%D0%B0-null">УПОРЯДОЧЕНИЕ С ПОМОЩЬЮ ОПРЕТОРА NULL</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-6">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-3">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-8-%D0%B7%D0%B0%D0%BF%D1%80%D0%B0%D1%88%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D1%8B%D1%85-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86-%D1%82%D0%B0%D0%BA%D0%B6%D0%B5-%D0%BA%D0%B0%D0%BA-%D0%BE%D0%B4%D0%BD%D0%BE%D0%B9">Глава 8. ЗАПРАШИВАНИЕ МНОГОЧИСЛЕНЫХ ТАБЛИЦ ТАКЖЕ КАК ОДНОЙ</a>
<ul>
<li><a href="#%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86">ОБЪЕДИНЕНИЕ ТАБЛИЦ</a></li>
<li><a href="#%D0%B8%D0%BC%D0%B5%D0%BD%D0%B0-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86-%D0%B8-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%BE%D0%B2">ИМЕНА ТАБЛИЦ И СТОЛБЦОВ</a></li>
<li><a href="#%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BE%D0%B1%D1%8C%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F">СОЗДАНИЕ ОБЬЕДИНЕНИЯ</a></li>
<li><a href="#%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86-%D1%87%D0%B5%D1%80%D0%B5%D0%B7-%D1%81%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%D1%87%D0%BD%D1%83%D1%8E-%D1%86%D0%B5%D0%BB%D0%BE%D1%81%D1%82%D0%BD%D0%BE%D1%81%D1%82%D1%8C">ОБЪЕДИНЕНИЕ ТАБЛИЦ ЧЕРЕЗ СПРАВОЧНУЮ ЦЕЛОСТНОСТЬ</a></li>
<li><a href="#%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86-%D0%BF%D0%BE-%D1%80%D0%B0%D0%B2%D0%B5%D0%BD%D1%81%D1%82%D0%B2%D1%83-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B2-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%B0%D1%85-%D0%B8-%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D0%B2%D0%B8%D0%B4%D1%8B-%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B9">ОБЪЕДИНЕНИЯ ТАБЛИЦ ПО РАВЕНСТВУ ЗНАЧЕНИЙ В СТОЛБЦАХ И ДРУГИЕ ВИДЫ ОБЪЕДИНЕНИЙ</a></li>
<li><a href="#%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B1%D0%BE%D0%BB%D0%B5%D0%B5-%D0%B4%D0%B2%D1%83%D1%85-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86">ОБЪЕДИНЕНИЕ БОЛЕЕ ДВУХ ТАБЛИЦ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-7">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-4">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-14-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-union">Глава 14. ИСПОЛЬЗОВАНИЕ ПРЕДЛОЖЕНИЯ UNION</a>
<ul>
<li><a href="#%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D0%B2-%D0%BE%D0%B4%D0%B8%D0%BD">ОБЪЕДИНЕНИЕ МНОГОЧИСЛЕННЫХ ЗАПРОСОВ В ОДИН</a></li>
<li><a href="#union">UNION</a></li>
<li><a href="#%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0-%D0%B2%D1%8B-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82%D0%B5-%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C-%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BC%D0%B5%D0%B6%D0%B4%D1%83-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0%D0%BC%D0%B8">КОГДА ВЫ МОЖЕТЕ ДЕЛАТЬ ОБЪЕДИНЕНИЕ МЕЖДУ ЗАПРОСАМИ?</a></li>
<li><a href="#union-%D0%B8-%D1%83%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B4%D1%83%D0%B1%D0%BB%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D0%B2">UNION И УСТРАНЕНИЕ ДУБЛИКАТОВ</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D1%80%D0%BE%D0%BA-%D0%B8-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9-%D1%81-union">ИСПОЛЬЗОВАНИЕ СТРОК И ВЫРАЖЕНИЙ С UNION</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-union-%D1%81-order-by">ИСПОЛЬЗОВАНИЕ UNION С ORDER BY</a></li>
<li><a href="#%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B5%D0%B5-%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5">ВНЕШНЕЕ ОБЪЕДИНЕНИЕ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-8">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-5">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-15-%D0%B2%D0%B2%D0%BE%D0%B4-%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9">Глава 15. ВВОД, УДАЛЕНИЕ и ИЗМЕНЕНИЕ ЗНАЧЕНИЙ ПОЛЕЙ</a>
<ul>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B-%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%B8-%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0-dml">КОМАНДЫ МОДИФИКАЦИИ ЯЗЫКА DML</a></li>
<li><a href="#%D0%B2%D1%81%D1%82%D0%B0%D0%B2%D0%BA%D0%B0-%D0%BF%D1%83%D1%81%D1%82%D1%8B%D1%85-%D1%83%D0%BA%D0%B0%D0%B7%D0%B0%D1%82%D0%B5%D0%BB%D0%B5%D0%B9-null">ВСТАВКА ПУСТЫХ УКАЗАТЕЛЕЙ (NULL)</a></li>
<li><a href="#%D0%B2%D1%81%D1%82%D0%B0%D0%B2%D0%BA%D0%B0-%D1%80%D0%B5%D0%B7%D1%83%D0%BB%D1%8C%D1%82%D0%B0%D1%82%D0%BE%D0%B2-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">ВСТАВКА РЕЗУЛЬТАТОВ ЗАПРОСА</a></li>
<li><a href="#delete-from-salespeople">DELETE FROM Salespeople;</a></li>
<li><a href="#%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%BF%D0%BE%D0%BB%D1%8F">ИЗМЕНЕНИЕ ЗНАЧЕНИЙ ПОЛЯ</a></li>
<li><a href="#%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D1%81%D1%82%D1%80%D0%BE%D0%BA">МОДИФИЦИРОВАНИЕ ТОЛЬКО ОПРЕДЕЛЕННЫХ СТРОК</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-update-%D0%B4%D0%BB%D1%8F-%D0%BC%D0%BD%D0%BE%D0%B3%D0%B8%D1%85-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%BE%D0%B2">КОМАНДА UPDATE ДЛЯ МНОГИХ СТОЛБЦОВ</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B2%D1%8B%D1%80%D0%B0%D0%B6%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B4%D0%BB%D1%8F-%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%B8">ИСПОЛЬЗОВАНИЕ ВЫРАЖЕНИЙ ДЛЯ МОДИФИКАЦИИ</a></li>
<li><a href="#%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%83%D1%81%D1%82%D1%8B%D1%85null-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9">МОДИФИЦИРОВАНИЕ ПУСТЫХ(NULL) ЗНАЧЕНИЙ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-9">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-6">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-16-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE%D0%B4%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D1%81-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0%D0%BC%D0%B8-%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%B8">Глава 16. ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С КОМАНДАМИ МОДИФИКАЦИИ</a>
<ul>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE%D0%B4%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D1%81-insert">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С INSERT</a></li>
<li><a href="#%D0%BD%D0%B5-%D0%B2%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D1%8F%D0%B9%D1%82%D0%B5-%D0%B4%D1%83%D0%B1%D0%BB%D0%B8%D0%BA%D0%B0%D1%82%D1%8B-%D1%81%D1%82%D1%80%D0%BE%D0%BA">НЕ ВСТАВЛЯЙТЕ ДУБЛИКАТЫ СТРОК</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE%D0%B4%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D1%8B%D1%85-%D0%B2%D0%BE-%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B5%D0%B9-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B5-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ СОЗДАНЫХ ВО ВНЕШНЕЙ ТАБЛИЦЕ ЗАПРОСА</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE%D0%B4%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D1%81-delete">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С DELETE</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE%D0%B4%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D1%81-update">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С UPDATE</a></li>
<li><a href="#%D1%81%D1%82%D0%BE%D0%BB%D0%BA%D0%BD%D0%BE%D0%B2%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC%D0%B8-%D0%BF%D0%BE%D0%B4%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%8B-dml">СТОЛКНОВЕНИЕ С ОГРАНИЧЕНИЯМИ ПОДЗАПРОСОВ КОМАНДЫ DML</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-10">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-7">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-17-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86">Глава 17. СОЗДАНИЕ ТАБЛИЦ</a>
<ul>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D1%8F-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B">КОМАНДА СОЗДАНИЯ ТАБЛИЦЫ</a></li>
<li><a href="#%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D1%8B">ИНДЕКСЫ</a></li>
<li><a href="#%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C-%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0">УНИКАЛЬНОСТЬ ИНДЕКСА</a></li>
<li><a href="#%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%BE%D0%B2">УДАЛЕНИЕ ИНДЕКСОВ</a></li>
<li><a href="#%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86">УДАЛЕНИЕ ТАБЛИЦ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-11">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-8">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-18%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B2%D0%B0%D1%88%D0%B8%D1%85-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">Глава 18.ОГРАНИЧЕНИЕ ЗНАЧЕНИЙ ВАШИХ ДАННЫХ</a>
<ul>
<li><a href="#%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86">ОГРАНИЧЕНИЕ ТАБЛИЦ</a></li>
<li><a href="#%D0%BE%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B9">ОБЪЯВЛЕНИЕ ОГРАНИЧЕНИЙ</a></li>
<li><a href="#%D1%83%D0%B1%D0%B5%D0%B4%D0%B8%D1%82%D0%B5%D1%81%D1%8C-%D1%87%D1%82%D0%BE-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F---%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B">УБЕДИТЕСЬ ЧТО ЗНАЧЕНИЯ - УНИКАЛЬНЫ</a></li>
<li><a href="#%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C-%D0%BA%D0%B0%D0%BA-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%B0">УНИКАЛЬНОСТЬ КАК ОГРАНИЧЕНИЕ СТОЛБЦА</a></li>
<li><a href="#%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C-%D0%BA%D0%B0%D0%BA-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B">УНИКАЛЬНОСТЬ КАК ОГРАНИЧЕНИЕ ТАБЛИЦЫ</a></li>
<li><a href="#%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%B5%D1%80%D0%B2%D0%B8%D1%87%D0%BD%D1%8B%D1%85-%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%B9">ОГРАНИЧЕНИЕ ПЕРВИЧНЫХ КЛЮЧЕЙ</a></li>
<li><a href="#%D0%BF%D0%B5%D1%80%D0%B2%D0%B8%D1%87%D0%BD%D1%8B%D0%B5-%D0%BA%D0%BB%D1%8E%D1%87%D0%B8-%D0%B1%D0%BE%D0%BB%D0%B5%D0%B5-%D1%87%D0%B5%D0%BC-%D0%BE%D0%B4%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BF%D0%BE%D0%BB%D1%8F">ПЕРВИЧНЫЕ КЛЮЧИ БОЛЕЕ ЧЕМ ОДНОГО ПОЛЯ</a></li>
<li><a href="#%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B9">ПРОВЕРКА ЗНАЧЕНИЙ ПОЛЕЙ</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5---check-%D1%87%D1%82%D0%BE%D0%B1%D1%8B-%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D1%8F%D1%82%D1%8C-%D0%B4%D0%BE%D0%BF%D1%83%D1%81%D1%82%D0%B8%D0%BC%D0%BE%D0%B5-%D0%B2%D0%B2%D0%BE%D0%B4%D0%B8%D0%BC%D0%BE%D0%B5-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5">ИСПОЛЬЗОВАНИЕ - CHECK, ЧТОБЫ ПРЕДОПРЕДЕЛЯТЬ ДОПУСТИМОЕ ВВОДИМОЕ ЗНАЧЕНИЕ</a></li>
<li><a href="#%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D1%83%D1%81%D0%BB%D0%BE%D0%B2%D0%B8%D0%B9-%D0%B1%D0%B0%D0%B7%D0%B8%D1%80%D1%83%D1%8E%D1%89%D0%B8%D0%B9%D1%81%D1%8F-%D0%BD%D0%B0-%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D1%87%D0%B8%D1%81%D0%BB%D0%B5%D0%BD%D1%8B%D1%85-%D0%BF%D0%BE%D0%BB%D1%8F%D1%85">ПРОВЕРКА УСЛОВИЙ БАЗИРУЮЩИЙСЯ НА МНОГОЧИСЛЕНЫХ ПОЛЯХ</a></li>
<li><a href="#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%BF%D0%BE-%D1%83%D0%BC%D0%BE%D0%BB%D1%87%D0%B0%D0%BD%D0%B8%D1%8E">УСТАНОВКА ЗНАЧЕНИЙ ПО УМОЛЧАНИЮ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-12">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-9">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-19-%D0%BF%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%BA%D0%B0-%D1%86%D0%B5%D0%BB%D0%BE%D1%81%D1%82%D0%BD%D0%BE%D1%81%D1%82%D0%B8-%D0%B2%D0%B0%D1%88%D0%B8%D1%85-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">Глава 19. ПОДДЕРЖКА ЦЕЛОСТНОСТИ ВАШИХ ДАННЫХ</a>
<ul>
<li><a href="#%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9-%D0%BA%D0%BB%D1%8E%D1%87-%D0%B8-%D1%80%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D0%B9-%D0%BA%D0%BB%D1%8E%D1%87">ВНЕШНИЙ КЛЮЧ И РОДИТЕЛЬСКИЙ КЛЮЧ</a></li>
<li><a href="#%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%BE%D0%B2%D1%8B%D0%B5-%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BB%D1%8E%D1%87%D0%B8">МНОГО-СТОЛБЦОВЫЕ ВНЕШНИЕ КЛЮЧИ</a></li>
<li><a href="#%D1%81%D0%BC%D1%8B%D1%81%D0%BB-%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B5%D0%B3%D0%BE-%D0%B8-%D1%80%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%BE%D0%B3%D0%BE-%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%B9">СМЫСЛ ВНЕШНЕГО И РОДИТЕЛЬСКОГО КЛЮЧЕЙ</a></li>
<li><a href="#%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-foreign-key">ОГРАНИЧЕНИЕ FOREIGN KEY</a></li>
<li><a href="#%D0%BA%D0%B0%D0%BA-%D0%BC%D0%BE%D0%B6%D0%BD%D0%BE-%D0%BF%D0%BE%D0%BB%D1%8F-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%B8%D1%82%D1%8C-%D0%B2-%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B5-%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D1%85-%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%B9">КАК МОЖНО ПОЛЯ ПРЕДСТАВИТЬ В КАЧЕСТВЕ ВНЕШНИХ КЛЮЧЕЙ</a></li>
<li><a href="#%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9-%D0%BA%D0%BB%D1%8E%D1%87-%D0%BA%D0%B0%D0%BA-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B">ВНЕШНИЙ КЛЮЧ КАК ОГРАНИЧЕНИЕ ТАБЛИЦЫ</a></li>
<li><a href="#%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9-%D0%BA%D0%BB%D1%8E%D1%87-%D0%BA%D0%B0%D0%BA-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%BE%D0%B2">ВНЕШНИЙ КЛЮЧ КАК ОГРАНИЧЕНИЕ СТОЛБЦОВ</a></li>
<li><a href="#%D0%BD%D0%B5-%D1%83%D0%BA%D0%B0%D0%B7%D1%8B%D0%B2%D0%B0%D1%82%D1%8C-%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%BE%D0%B2-%D0%BF%D0%B5%D1%80%D0%B2%D0%B8%D1%87%D0%BD%D1%8B%D1%85-%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%B9">НЕ УКАЗЫВАТЬ СПИСОК СТОЛБЦОВ ПЕРВИЧНЫХ КЛЮЧЕЙ</a></li>
<li><a href="#%D0%BA%D0%B0%D0%BA-%D1%81%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%D1%87%D0%BD%D0%B0%D1%8F-%D1%86%D0%B5%D0%BB%D0%BE%D1%81%D1%82%D0%BD%D0%BE%D1%81%D1%82%D1%8C-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B8%D0%B2%D0%B0%D0%B5%D1%82-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F-%D1%80%D0%BE%D0%B4%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%BE%D0%B3%D0%BE-%D0%BA%D0%BB%D1%8E%D1%87%D0%B0">КАК СПРАВОЧНАЯ ЦЕЛОСТНОСТЬ ОГРАНИЧИВАЕТ ЗНАЧЕНИЯ РОДИТЕЛЬСКОГО КЛЮЧА</a></li>
<li><a href="#%D0%BF%D0%B5%D1%80%D0%B2%D0%B8%D1%87%D0%BD%D1%8B%D0%B9-%D0%BA%D0%BB%D1%8E%D1%87-%D0%BA%D0%B0%D0%BA-%D1%83%D0%BD%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9-%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B9-%D0%BA%D0%BB%D1%8E%D1%87">ПЕРВИЧНЫЙ КЛЮЧ КАК УНИКАЛЬНЫЙ ВНЕШНИЙ КЛЮЧ</a></li>
<li><a href="#%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B5%D0%B3%D0%BE-%D0%BA%D0%BB%D1%8E%D1%87%D0%B0">ОГРАНИЧЕНИЯ ВНЕШНЕГО КЛЮЧА</a></li>
<li><a href="#%D1%87%D1%82%D0%BE-%D1%81%D0%BB%D1%83%D1%87%D0%B8%D1%82%D1%81%D1%8F-%D0%B5%D1%81%D0%BB%D0%B8-%D0%B2%D1%8B-%D0%B2%D1%8B%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5-%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D1%83-%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D0%BA%D0%B0%D1%86%D0%B8%D0%B8">ЧТО СЛУЧИТСЯ, ЕСЛИ ВЫ ВЫПОЛНИТЕ КОМАНДУ МОДИФИКАЦИИ</a></li>
<li><a href="#%D0%B2%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B9-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B">ВКЛЮЧЕНИЕ ОПИСАНИЙ ТАБЛИЦЫ</a></li>
<li><a href="#%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B5-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B9">ДЕЙСТВИЕ ОГРАНИЧЕНИЙ</a></li>
<li><a href="#%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BB%D1%8E%D1%87%D0%B8-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D1%81%D1%81%D1%8B%D0%BB%D0%B0%D1%8E%D1%82%D1%81%D1%8F-%D0%BE%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D0%BE-%D0%BA-%D0%B8%D1%85-%D0%BF%D0%BE%D0%B4%D1%87%D0%B8%D0%BD%D0%B5%D0%BD%D1%8B%D0%BC-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0%D0%BC">ВНЕШНИЕ КЛЮЧИ КОТОРЫЕ ССЫЛАЮТСЯ ОБРАТНО К ИХ ПОДЧИНЕНЫМ ТАБЛИЦАМ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-13">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-10">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-20-%D0%B2%D0%B2%D0%B5%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F">Глава 20. ВВЕДЕНИЕ: ПРЕДСТАВЛЕНИЯ</a>
<ul>
<li><a href="#%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">ЧТО ТАКОЕ ПРЕДСТАВЛЕНИЕ?</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-create-view">КОМАНДА CREATE VIEW</a></li>
<li><a href="#%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9">МОДИФИЦИРОВАНИЕ ПРЕДСТАВЛЕНИЙ</a></li>
<li><a href="#%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D0%BE%D0%B2">ИМЕНОВАНИЕ СТОЛБЦОВ</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B1%D0%B8%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D0%B8%D0%BA%D0%B0%D1%82%D0%BE%D0%B2-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B8-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D1%8B%D1%85-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%BE%D0%B2-%D0%B2-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%D1%85">КОМБИНИРОВАНИЕ ПРЕДИКАТОВ ПРЕДСТАВЛЕНИЙ И ОСНОВНЫХ ЗАПРОСОВ В ПРЕДСТАВЛЕНИЯХ</a></li>
<li><a href="#%D0%B3%D1%80%D1%83%D0%BF%D0%BF%D0%BE%D0%B2%D1%8B%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F">ГРУППОВЫЕ ПРЕДСТАВЛЕНИЯ</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8-%D0%BE%D0%B1%D1%8C%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F">ПРЕДСТАВЛЕНИЯ И ОБЬЕДИНЕНИЯ</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8-%D0%BF%D0%BE%D0%B4%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D1%8B">ПРЕДСТАВЛЕНИЯ И ПОДЗАПРОСЫ</a></li>
<li><a href="#%D1%87%D1%82%D0%BE-%D0%BD%D0%B5-%D0%BC%D0%BE%D0%B3%D1%83%D1%82-%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F">ЧТО НЕ МОГУТ ДЕЛАТЬ ПРЕДСТАВЛЕНИЯ</a></li>
<li><a href="#%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9">УДАЛЕНИЕ ПРЕДСТАВЛЕНИЙ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-14">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-11">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-21-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9">Глава 21. ИЗМЕНЕНИЕ ЗНАЧЕНИЙ С ПОМОЩЬЮ ПРЕДСТАВЛЕНИЙ</a>
<ul>
<li><a href="#%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F">МОДИФИЦИРОВАНИЕ ПРЕДСТАВЛЕНИЯ</a></li>
<li><a href="#%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D0%B8-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F">ОПРЕДЕЛЕНИЕ МОДИФИЦИРУЕМОСТИ ПРЕДСТАВЛЕНИЯ</a></li>
<li><a href="#%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D1%8B%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B8-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE_%D1%87%D1%82%D0%B5%D0%BD%D0%B8%D0%B5">МОДИФИЦИРУЕМЫЕ ПРЕДСТАВЛЕНИЯ И ПРЕДСТАВЛЕНИЯ ТОЛЬКО_ЧТЕНИЕ.</a></li>
<li><a href="#%D1%87%D1%82%D0%BE-%D1%8F%D0%B2%D0%BB%D1%8F%D0%B5%D1%82%D1%81%D1%8F---%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D1%83%D0%B5%D0%BC%D1%8B%D0%BC%D0%B8-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5%D0%BC">ЧТО ЯВЛЯЕТСЯ - МОДИФИЦИРУЕМЫМИ ПРЕДСТАВЛЕНИЕМ</a></li>
<li><a href="#%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%BF%D0%BE%D0%BC%D0%B5%D1%89%D0%B0%D0%B5%D0%BC%D1%8B%D1%85-%D0%B2-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5">ПРОВЕРКА ЗНАЧЕНИЙ ПОМЕЩАЕМЫХ В ПРЕДСТАВЛЕНИЕ</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%B8%D0%BA%D0%B0%D1%82%D1%8B-%D0%B8-%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D0%BF%D0%BE%D0%BB%D1%8F">ПРЕДИКАТЫ И ИСКЛЮЧЕННЫЕ ПОЛЯ</a></li>
<li><a href="#%D0%BF%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9-%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D0%B1%D0%B0%D0%B7%D0%B8%D1%80%D1%83%D1%8E%D1%82%D1%81%D1%8F-%D0%BD%D0%B0-%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D1%85-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F%D1%85">ПРОВЕРКА ПРЕДСТАВЛЕНИЙ КОТОРЫЕ БАЗИРУЮТСЯ НА ДРУГИХ ПРЕДСТАВЛЕНИЯХ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-15">РЕЗЮМЕ</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-22-%D0%BA%D1%82%D0%BE-%D1%87%D1%82%D0%BE-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82-%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C-%D0%B2-%D0%B1%D0%B0%D0%B7%D0%B5-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">Глава 22. КТО ЧТО МОЖЕТ ДЕЛАТЬ В БАЗЕ ДАННЫХ</a>
<ul>
<li><a href="#%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B8">ПОЛЬЗОВАТЕЛИ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B3%D0%B8%D1%81%D1%82%D1%80%D0%B0%D1%86%D0%B8%D1%8F">РЕГИСТРАЦИЯ</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9">ПРЕДОСТАВЛЕНИЕ ПРИВИЛЕГИЙ</a></li>
<li><a href="#%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5-%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B8">СТАНДАРТНЫЕ ПРИВИЛЕГИИ</a></li>
<li><a href="#%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9-%D0%BD%D0%B0-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D0%B5-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D1%8B">ОГРАНИЧЕНИЕ ПРИВИЛЕГИЙ НА ОПРЕДЕЛЕННЫЕ СТОЛБЦЫ</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9-%D1%81-%D0%BF%D0%BE%D0%BC%D0%BE%D1%89%D1%8C%D1%8E-with-grant-option">ПРЕДОСТАВЛЕНИЕ ПРИВЕЛЕГИЙ С ПОМОЩЬЮ WITH GRANT OPTION</a></li>
<li><a href="#%D0%BE%D1%82%D0%BC%D0%B5%D0%BD%D0%B0-%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9">ОТМЕНА ПРИВИЛЕГИЙ</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B4%D0%BB%D1%8F-%D1%84%D0%B8%D0%BB%D1%8C%D1%82%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9">ИСПОЛЬЗОВАНИЕ ПРЕДСТАВЛЕНИЙ ДЛЯ ФИЛЬТРАЦИИ ПРИВЕЛЕГИЙ</a></li>
<li><a href="#%D0%BA%D1%82%D0%BE-%D0%BC%D0%BE%D0%B6%D0%B5%D1%82-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%B2%D0%B0%D1%82%D1%8C-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F">КТО МОЖЕТ СОЗДАВАТЬ ПРЕДСТАВЛЕНИЯ?</a></li>
<li><a href="#%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B8%D0%B2%D0%B5%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9-%D0%B4%D0%BB%D1%8F-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D1%81%D1%82%D1%80%D0%BE%D0%BA">ОГРАНИЧЕНИЕ ПРИВЕЛЕГИЙ ДЛЯ ОПРЕДЕЛЕННЫХ СТРОК</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B0-%D1%82%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE-%D0%BA-%D0%B8%D0%B7%D0%B2%D0%BB%D0%B5%D1%87%D0%B5%D0%BD%D0%BD%D1%8B%D0%BC-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%BC">ПРЕДОСТАВЛЕНИЕ ДОСТУПА ТОЛЬКО К ИЗВЛЕЧЕННЫМ ДАННЫМ</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B2-%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B5-%D0%B0%D0%BB%D1%8C%D1%82%D0%B5%D1%80%D0%BD%D0%B0%D1%82%D0%B8%D0%B2%D1%8B-%D0%BA-%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D1%8F%D0%BC">ИСПОЛЬЗОВАНИЕ ПРЕДСТАВЛЕНИЙ В КАЧЕСТВЕ АЛЬТЕРНАТИВЫ К ОГРАНИЧЕНИЯМ</a></li>
<li><a href="#%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B9">ДРУГИЕ ТИПЫ ПРИВИЛЕГИЙ</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D0%B8%D1%87%D0%BD%D1%8B%D0%B5-%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B8-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B">ТИПИЧНЫЕ ПРИВИЛЕГИИ СИСТЕМЫ</a></li>
<li><a href="#%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B8-%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D0%B5%D0%B9">СОЗДАНИЕ И УДАЛЕНИЕ ПОЛЬЗОВАТЕЛЕЙ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-16">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-12">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-23-%D0%B3%D0%BB%D0%BE%D0%B1%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%B0%D1%81%D0%BF%D0%B5%D0%BA%D1%82%D1%8B-sql">Глава 23. ГЛОБАЛЬНЫЕ АСПЕКТЫ SQL</a>
<ul>
<li><a href="#%D0%BF%D0%B5%D1%80%D0%B5%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86">ПЕРЕИМЕНОВАНИЕ ТАБЛИЦ</a></li>
<li><a href="#%D0%BF%D0%B5%D1%80%D0%B5%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D1%81-%D1%82%D0%B5%D0%BC-%D0%B6%D0%B5-%D1%81%D0%B0%D0%BC%D1%8B%D0%BC-%D0%B8%D0%BC%D0%B5%D0%BD%D0%B5%D0%BC">ПЕРЕИМЕНОВАНИЕ С ТЕМ ЖЕ САМЫМ ИМЕНЕМ</a></li>
<li><a href="#%D0%BE%D0%B4%D0%BD%D0%BE-%D0%B8%D0%BC%D1%8F-%D0%B4%D0%BB%D1%8F-%D0%BA%D0%B0%D0%B6%D0%B4%D0%BE%D0%B3%D0%BE">ОДНО ИМЯ ДЛЯ КАЖДОГО</a></li>
<li><a href="#%D1%83%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%81%D0%B8%D0%BD%D0%BE%D0%BD%D0%B8%D0%BC%D0%BE%D0%B2">УДАЛЕНИЕ СИНОНИМОВ</a></li>
<li><a href="#%D0%BA%D0%BE%D0%B3%D0%B4%D0%B0-%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-%D0%B8%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F-%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D1%8F%D1%82%D1%81%D1%8F-%D0%BF%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%BD%D1%8B%D0%BC%D0%B8">КОГДА СДЕЛАННЫЕ ИЗМЕНЕНИЯ СТАНОВЯТСЯ ПОСТОЯННЫМИ?</a></li>
<li><a href="#%D0%BA%D0%B0%D0%BA-sql-%D0%BE%D0%B1%D1%89%D0%B0%D0%B5%D1%82%D1%81%D1%8F-%D1%81%D1%80%D0%B0%D0%B7%D1%83-%D1%81%D0%BE-%D0%BC%D0%BD%D0%BE%D0%B3%D0%B8%D0%BC%D0%B8-%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8F%D0%BC%D0%B8">КАК SQL ОБЩАЕТСЯ СРАЗУ СО МНОГИМИ ПОЛЬЗОВАТЕЛЯМИ</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D1%8B-%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BE%D0%BA">ТИПЫ БЛОКИРОВОК</a></li>
<li><a href="#%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1%D1%8B-%D0%B1%D0%BB%D0%BE%D0%BA%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">ДРУГИЕ СПОСОБЫ БЛОКИРОВКИ ДАННЫХ</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-17">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-13">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-24-%D0%BA%D0%B0%D0%BA-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D0%B5-sql-%D1%81%D0%BE%D0%B4%D0%B5%D1%80%D0%B6%D0%B0%D1%82%D1%81%D1%8F-%D0%B2-%D1%83%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D1%87%D0%B5%D0%BD%D0%BD%D0%BE%D0%BC-%D0%B2%D0%B8%D0%B4%D0%B5">Глава 24. КАК ДАННЫЕ SQL СОДЕРЖАТСЯ В УПОРЯДОЧЕННОМ ВИДЕ</a>
<ul>
<li><a href="#%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D1%8B">КАТАЛОГ СИСТЕМЫ</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D0%B8%D1%87%D0%BD%D1%8B%D0%B9-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%BD%D1%8B%D0%B9-%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3">ТИПИЧНЫЙ СИСТЕМНЫЙ КАТАЛОГ</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B9-%D0%B2-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D0%B0%D1%85-%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3%D0%B0">ИСПОЛЬЗОВАНИЕ ПРЕДСТАВЛЕНИЙ В ТАБЛИЦАХ КАТАЛОГА</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%80%D0%B8%D0%B9-%D0%B2-%D1%81%D0%BE%D0%B4%D0%B5%D1%80%D0%B6%D0%B0%D0%BD%D0%B8%D0%B8-%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3%D0%B0">КОММЕНТАРИЙ В СОДЕРЖАНИИ КАТАЛОГА</a></li>
<li><a href="#%D0%BE%D1%81%D1%82%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5-%D0%B8%D0%B7-%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3%D0%B0">ОСТАЛЬНОЕ ИЗ КАТАЛОГА</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81">ТИПОВОЙ ЗАПРОС</a></li>
<li><a href="#systemuserauth---%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D1%81%D0%BA%D0%B8%D0%B5-%D0%B8-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%BD%D1%8B%D0%B5-%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B8-%D0%B2-%D0%B1%D0%B0%D0%B7%D0%B5-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">SYSTEMUSERAUTH - ПОЛЬЗОВАТЕЛЬСКИЕ И СИСТЕМНЫЕ ПРИВИЛЕГИИ В БАЗЕ ДАННЫХ</a></li>
<li><a href="#systemtabauth---%D0%BF%D1%80%D0%B8%D0%B2%D0%B8%D0%BB%D0%B5%D0%B3%D0%B8%D0%B8-%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82%D0%B0-%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D0%BD%D0%B5-%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D1%8F%D1%8E%D1%82-%D1%81%D1%82%D0%BE%D0%BB%D0%B1%D1%86%D1%8B">SYSTEMTABAUTH - ПРИВИЛЕГИИ ОБЪЕКТА ОТОРЫЕ НЕ ОПРЕДЕЛЯЮТ СТОЛБЦЫ</a></li>
<li><a href="#systemcolauth">SYSTEMCOLAUTH</a></li>
<li><a href="#systemsynons---%D1%81%D0%B8%D0%BD%D0%BE%D0%BD%D0%B8%D0%BC%D1%8B-%D0%B4%D0%BB%D1%8F-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86-%D0%B2-%D0%B1%D0%B0%D0%B7%D0%B5-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">SYSTEMSYNONS - СИНОНИМЫ ДЛЯ ТАБЛИЦ В БАЗЕ ДАННЫХ</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D0%BE%D0%B2%D0%BE%D0%B9-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81-1">ТИПОВОЙ ЗАПРОС.</a></li>
<li><a href="#%D0%B4%D1%80%D1%83%D0%B3%D0%BE%D0%B5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3%D0%B0">ДРУГОЕ ИСПОЛЬЗОВАНИЕ КАТАЛОГА</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-18">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-14">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-25-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-sql-%D1%81-%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%BC-%D1%8F%D0%B7%D1%8B%D0%BA%D0%BE%D0%BC">Глава 25. ИСПОЛЬЗОВАНИЕ SQL С ДРУГИМ ЯЗЫКОМ</a>
<ul>
<li><a href="#%D1%87%D1%82%D0%BE-%D1%82%D0%B0%D0%BA%D0%BE%D0%B5---%D0%B2%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-sql">ЧТО ТАКОЕ - ВЛОЖЕНИЕ SQL</a></li>
<li><a href="#%D0%B7%D0%B0%D1%87%D0%B5%D0%BC-%D0%B2%D0%BA%D0%BB%D0%B0%D0%B4%D1%8B%D0%B2%D0%B0%D1%82%D1%8C-sql">ЗАЧЕМ ВКЛАДЫВАТЬ SQL?</a></li>
<li><a href="#%D0%BA%D0%B0%D0%BA-%D0%B4%D0%B5%D0%BB%D0%B0%D1%8E%D1%82%D1%81%D1%8F-%D0%B2%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F-sql">КАК ДЕЛАЮТСЯ ВЛОЖЕНИЯ SQL.</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85-%D0%BE%D1%81%D0%BD%D0%BE%D0%B2%D0%BD%D0%BE%D0%B3%D0%BE-%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0-%D0%B2-sql">ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННЫХ ОСНОВНОГО ЯЗЫКА В SQL</a></li>
<li><a href="#%D0%BE%D0%B1%D1%8A%D1%8F%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85">ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ</a></li>
<li><a href="#%D0%B8%D0%B7%D0%B2%D0%BB%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D1%8B%D1%85">ИЗВЛЕЧЕНИЕ ЗНАЧЕНИЙ ПЕРЕМЕННЫХ</a></li>
<li><a href="#%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80">КУРСОР</a></li>
<li><a href="#sql-%D0%BA%D0%BE%D0%B4%D1%8B">SQL КОДЫ</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-sqlcode-%D0%B4%D0%BB%D1%8F-%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D1%86%D0%B8%D0%BA%D0%BB%D0%B0%D0%BC%D0%B8">ИСПОЛЬЗОВАНИЕ SQLCODE ДЛЯ УПРАВЛЕНИЯ ЦИКЛАМИ</a></li>
<li><a href="#%D0%BF%D1%80%D0%B5%D0%B4%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-whenever">ПРЕДЛОЖЕНИЕ WHENEVER</a></li>
<li><a href="#%D0%BC%D0%BE%D0%B4%D0%B8%D1%84%D0%B8%D1%86%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D1%83%D1%80%D1%81%D0%BE%D1%80%D0%BE%D0%B2">МОДИФИЦИРОВАНИЕ КУРСОРОВ</a></li>
<li><a href="#%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%B0%D1%8F-indicator">ПЕРЕМЕННАЯ INDICATOR</a></li>
<li><a href="#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9-indicator-%D0%B4%D0%BB%D1%8F-%D1%8D%D0%BC%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D0%B8-null-%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B9-sql">ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННОЙ INDICATOR ДЛЯ ЭМУЛЯЦИИ NULL ЗНАЧЕНИЙ SQL</a></li>
<li><a href="#%D0%B4%D1%80%D1%83%D0%B3%D0%BE%D0%B5-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BF%D0%B5%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%BD%D0%BE%D0%B9-indicator">ДРУГОЕ ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННОЙ INDICATOR</a></li>
<li><a href="#%D1%80%D0%B5%D0%B7%D1%8E%D0%BC%D0%B5-19">РЕЗЮМЕ</a></li>
<li><a href="#%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-sql-15">РАБОТА С SQL</a></li>
</ul>
</li>
<li><a href="#%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-a">Приложение A</a>
<ul>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-1">Глава 1</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-2">Глава 2</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-3">Глава 3</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-4">Глава 4</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-5">Глава 5</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-6">Глава 6</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-7">Глава 7</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-8">Глава 8</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-9">Глава 9</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-10">Глава 10</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-11">Глава 11</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-12">Глава 12</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-13">Глава 13</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-14">Глава 14</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-15">Глава 15</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-16">Глава 16</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-17">Глава 17</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-18">Глава 18</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-19">Глава 19</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-20">Глава 20</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-21">Глава 21</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-22">Глава 22</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-23">Глава 23</a></li>
<li><a href="#%D0%B3%D0%BB%D0%B0%D0%B2%D0%B0-24">Глава 24</a></li>
</ul>
</li>
<li><a href="#%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-b">Приложение B</a>
<ul>
<li><a href="#%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2-sql">ТИПЫ ДАННЫХ В SQL</a>
<ul>
<li><a href="#%D1%82%D0%B8%D0%BF%D1%8B-ansi">ТИПЫ ANSI</a>
<ul>
<li><a href="#text%D1%82%D0%B5%D0%BA%D1%81%D1%82">TEXT	ТЕКСТ</a></li>
<li><a href="#exact-numeric">EXACT NUMERIC</a></li>
<li><a href="#dec-%D0%B8%D0%BB%D0%B8-decimal">DEC (или DECIMAL)</a></li>
<li><a href="#numeric">NUMERIC</a></li>
<li><a href="#int-%D0%B8%D0%BB%D0%B8-integer">INT( или INTEGER)</a></li>
<li><a href="#smallint">SMALLINT</a></li>
<li><a href="#approximate-numeric">APPROXIMATE NUMERIC</a></li>
<li><a href="#float">FLOAT</a></li>
<li><a href="#real">REAL</a></li>
<li><a href="#double-precision--%D0%B8%D0%BB%D0%B8-double-">DOUBLE PRECISION ( или DOUBLE )</a></li>
</ul>
</li>
<li><a href="#%D1%8D%D0%BA%D0%B2%D0%B8%D0%B2%D0%B0%D0%BB%D0%B5%D0%BD%D1%82%D0%BD%D1%8B%D0%B5-%D1%82%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85-%D0%B2-%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D1%85-%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0%D1%85">ЭКВИВАЛЕНТНЫЕ ТИПЫ ДАННЫХ В ДРУГИХ ЯЗЫКАХ</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-c">Приложение C</a>
<ul>
<li><a href="#%D0%BD%D0%B5%D0%BA%D0%BE%D1%82%D0%BE%D1%80%D1%8B%D0%B5-%D0%BE%D0%B1%D1%89%D0%B8%D0%B5-h%D0%B5%D1%81%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82%D0%BD%D1%8B%D0%B5-%D1%81%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B2%D0%B0-sql">НЕКОТОРЫЕ ОБЩИЕ HЕСТАНДАРТНЫЕ СРЕДСТВА SQL</a>
<ul>
<li><a href="#t%D0%B8%D0%BF%D1%8B-%D0%B4%D0%B0%D0%BD%D0%BD%D1%8B%D1%85">TИПЫ ДАННЫХ</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D1%8B-date-%D0%B8-time">ТИПЫ DATE И TIME</a></li>
<li><a href="#%D1%82%D0%B8%D0%BF%D1%8B-%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BE%D0%B2%D0%BE%D0%B9-%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8">ТИПЫ ТЕКСТОВОЙ СТРОКИ</a></li>
<li><a href="#%D0%BA%D0%BE%D0%BC%D0%B0%D0%BD%D0%B4%D0%B0-format">КОМАНДА FORMAT</a></li>
<li><a href="#%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">ФУНКЦИИ</a>
<ul>
<li><a href="#%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">МАТЕМАТИЧЕСКИЕ ФУНКЦИИ</a></li>
<li><a href="#%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">СИМВОЛЬНЫЕ ФУНКЦИИ</a></li>
<li><a href="#%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8-%D0%B4%D0%B0%D1%82%D1%8B-%D0%B8-%D0%B2%D1%80%D0%B5%D0%BC%D0%B5%D0%BD%D0%B8">ФУНКЦИИ ДАТЫ И ВРЕМЕНИ</a></li>
<li><a href="#%D0%B4%D1%80%D1%83%D0%B3%D0%B8%D0%B5-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D0%B8">ДРУГИЕ ФУНКЦИИ</a></li>
<li><a href="#intersect-%D0%B8-minus">INTERSECT И MINUS</a></li>
</ul>
</li>
<li><a href="#%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D0%B5-%D0%B2%D0%BD%D0%B5%D1%88%D0%BD%D0%B8%D0%B5-%D0%BE%D0%B1%D1%8A%D0%B5%D0%B4%D0%B8%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F">АВТОМАТИЧЕСКИЕ ВНЕШНИЕ ОБЪЕДИНЕНИЯ</a></li>
<li><a href="#%D0%BE%D1%82%D1%81%D0%BB%D0%B5%D0%B6%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%B4%D0%B5%D0%B9%D1%81%D1%82%D0%B2%D0%B8%D0%B9">ОТСЛЕЖИВАНИЕ ДЕЙСТВИЙ</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5-e">Приложение E</a>
<ul>
<li><a href="#%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D1%83%D0%B5%D0%BC%D1%8B%D0%B5-%D0%B2-sql">ТАБЛИЦЫ, ИСПОЛЬЗУЕМЫЕ В SQL</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- End Document Outline -->
<h1 id="понимание-sql">Понимание SQL</h1>
<h1 id="команда-select">Команда SELECT</h1>
<pre><code>   SELECT * | { [ DISTINCT | ALL] &lt;value expression&gt;.,..}
    FROM { &lt;table name&gt; [ &lt;alias&gt; ] }.,..
    [ WHERE &lt;predicate&gt;]
    [ GROUP BY { &lt;column name&gt; | &lt;integer&gt; }.,..]
    [ HAVING &lt;predicate&gt;]
    [ ORDERBY { &lt;column name&gt; | &lt;integer&gt; }.,..]
    [ { UNION [ALL]
 
 
   SELECT * | { [DISTINCT | ALL] &lt; value expression &gt;.,..}
    FROM { &lt;table name&gt; [&lt;alias&gt;]} .,..
    [ WHERE &lt;predicate&gt;
    [ GROUP BY { &lt;columnname&gt; | &lt;integer&gt; }.,..]
    [ HAVING &lt;predicate&gt;]
    [ ORDER BY { &lt;columnname&gt; | &lt;integer&gt; }.,..] } ] ...;
   Элементы, используемые в команде SELECT
</code></pre>
<table>
<thead>
<tr>
<th>   ЭЛЕМЕНТ</th>
<th>   ОПРЕДЕЛЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   &lt;value expression&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Выражение, которое производит значение. Оно может включать в себя или содержать &lt;column name&gt;.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;table name&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя или синоним таблицы или представления<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;alias&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Временный синоним для &lt;table name&gt;, определеный в этой таблице и используемый только в этой команде<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;predicate&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Условие , которое может быть верным или неверным для каждой строки или комбинации строк таблицы в предложении FROM.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;column name&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя столбца в таблице.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;integer&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Число с десятичной точкой. В этом случае, оно показывает &lt;value expression&gt; в предложении SELECT с помощью идентификации его местоположения в этом предложении.<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<h1 id="команды-update-insert-delete">Команды UPDATE, INSERT, DELETE</h1>
<h2 id="update">UPDATE</h2>
<pre><code>   UPDATE &lt;tablename&gt;
    SET { | }.,. .&lt; column name&gt; = &lt;value expresslon&gt; [ WHERE &lt;predlcate&gt;
    | WHERE CURRENT OF &lt;cursor name&gt; (*только для вложения*) ];
</code></pre>
<h2 id="insert">INSERT</h2>
<pre><code>   INSERT INTO &lt; table name&gt; [(&lt;column name&gt; .,. ]
    { VALUES ( &lt;value expression&gt; .,.. ) } | &lt;query&gt;;
</code></pre>
<h2 id="delete">DELETE</h2>
<pre><code>   DELETE FROM &lt;table name&gt;
    [ WHERE &lt;predicate&gt;
    | WHERE CURRENT OF &lt;cursor name&gt; (*только для вложения*) ];
Элементы, используемые в командах МОДИФИКАЦИИ
</code></pre>
<table>
<thead>
<tr>
<th>   ЭЛЕМЕНТ</th>
<th>   ОПРЕДЕЛЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   &lt;cursor name&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя курсора используемого в этой программе.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;query&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Допустимая команда SELECT.<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Допустимая команда SELECT.</p>
<p>Для других элементов смотри команду SELECT.
Символы Используемые в Синтаксисе Предлжения</p>
<table>
<thead>
<tr>
<th>   СИМВОЛ</th>
<th>   ОБЪЯСНЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>|<br style="margin: 0px; padding: 0px;"></td>
<td>   Любой предшествующий знаку (|) символ может быть произвольно<br style="margin: 0px; padding: 0px;">   заменен на любой следующий за (|). Это — символический способ высказывания &quot;или&quot; (&quot;or&quot;).<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   { }<br style="margin: 0px; padding: 0px;"></td>
<td>   Все, что включено в фигурные скобки обрабатывается как модуль с целью оценки |, .,.. или других символов.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   [ ]<br style="margin: 0px; padding: 0px;"></td>
<td>   Все,включенное в квадратные скобки является необязательным<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   ...<br style="margin: 0px; padding: 0px;"></td>
<td>   Любое, предшествующее этому, может повторяться любое число раз.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   .,..<br style="margin: 0px; padding: 0px;"></td>
<td>   Любое, предшествующее этому, и в каждом случае отделенное<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<h1 id="команда-create-table">Команда CREATE TABLE</h1>
<pre><code>CREATE TABLE &lt;table name&gt;
( { &lt;column name&gt; &lt;data type&gt; | &lt;size&gt;]
[&lt;colcnstrnt&gt; ...]} .,.. );
[&lt;tabconstrnt&gt;] .,.. );
</code></pre>
<p>Элементы, используемые в команде CREATE TABLE</p>
<table>
<thead>
<tr>
<th>   ЭЛЕМЕНТ</th>
<th>   ОПРЕДЕЛЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   &lt;table name&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя таблицы создаваемой этой командой.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;column name&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя столбца таблицы.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   &lt;data type&gt;<br style="margin: 0px; padding: 0px;"></td>
<td>   Тип данных<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Тип данных, который может содержаться в столбце.
Может быть любым из следующих:</p>
<pre><code>INTEGER (ЦЕЛОЕ ЧИСЛО),
CHARACTER (СИМВОЛЬНОЕ),
DECIMAL (ДЕСЯТИЧНОЕ),
NUMERIC (ЧИСЛОВОЕ),
SMALLINT (НАИМЕНЬШЕЕ)

FLOAT (С ПЛАВАЮЩЕЙ ТОЧКОЙ)

REAL (РЕАЛЬНОЕ),
DOUBLE PRECISION (УДВОЕННАЯ ТОЧНОСТЬ С ПЛАВАЮЩЕЙ ТОЧКОЙ),
LONG * (ДЛИННОЕ *),
VARCHAR * (ПЕРЕМЕННОЕ СИМВОЛЬНОЕ *),
DATE * (ДАТА *),
TIME * (ВРЕМЯ *)
</code></pre>
<p>(* — указывает на нестандартный для SQL тип данных)</p>
<p><size> Размер. Его значение зависит от <data type="">.
<colconstrnt> Может быть любым из следующих:</colconstrnt></data></size></p>
<pre><code>NOT NULL (НЕ НУЛЕВОЙ),
UNIQUE (УНИКАЛЬНЫЙ),
PRIMARY KEY (ПЕРВИЧНЫЙ КЛЮЧ),
CHECK(&lt;predicate&gt;) (ПРОВЕРКА предиката),
DEFAULT = &lt;value expression&gt; (ПО УМОЛЧАНИЮ = значимому выражению)
REFERENCES &lt;table name&gt; [(&lt;column name&gt; .,.. )] (ССЫЛКА НА имя таблицы [(имя столбца) ] )
&lt;tabconstrnt&gt; Может быть любым из следующих:
UNIQUE (УНИКАЛЬНЫЙ),
PRIMARY KEY (ПЕРВИЧНЫЙ КЛЮЧ),
CHECK (ПРОВЕРКА предиката )
FOREIGN KEY(&lt;column name&gt;) (ВНЕШНИЙ КЛЮЧ)
REFERENCES &lt;table name&gt; [(&lt;column name&gt; .,.. )] (ССЫЛКА НА имя таблицы [( имя столбца) ].
 
</code></pre>
<h1 id="предисловие">ПРЕДИСЛОВИЕ</h1>
<p>&quot;ПОНИМАНИЕ SQL&quot; - это полный учебник по программированию на Структурированном Языке Запросов, написанный специально для тех, кто будет использовать SQL в процессе работы. Даже если это ваш первый опыт с компьютерами или управлением базами данных, книга &quot;ПОНИМАНИЕ SQL&quot; очень быстро научит вас свободно работать с реальной SQL, использованию простых запросов, а также снабдит вас ясными понятиями об автоматизированном управлении базой данных. Книга даст вам краткое, удобное в чтении введение в реляционные базы данных. Предоставит вам обучающие программы, чтобы, овладевая командами SQL шаг за шагом, помочь вам узнать, как извлекать и обрабатывать информацию, содержащуюся в таблицах данных, т.е.:</p>
<ul>
<li>выбирать информацию, с которой вы хотите работать</li>
<li>добавлять, удалять, и модифицировать информацию в таблице данных</li>
<li>использовать и-или, верно/неверно и другие условия для обнуления определенной информации</li>
<li>использовать специальные функции SQL для суммирования ваших данных.
Книга покажет Вам, как эффективно работать с многочислеными таблицами данных, используя улучшеную технику для запроса более чем одной таблицы одновременно, строить комплекс запросов и подзапросов, и использовать представления, чтобы создавать базы данных и работать с базами данных раздельно с многими таблицами.
Научит создавать новые таблицы данных для пользовательских деловых прикладных программ. Вы исследуете принципы эффективного проектирования базы данных, а также техники для обеспечения целостности данных и их защиты.
Вы узнаете, как использовать SQL с другими языками в специальной главе SQL для программистов.
&quot;ПОНИМАНИЕ SQL&quot; - необходима и пригодна для любой реализации Структурированного Языка Запроса. Книга включает и краткий справочный стандарт SQL и руководство к общим нестандартным особенностям SQL.
Об Авторе
Мартин Грубер - свободный писатель, учитель и консультант из Сан-Франциско.
В дополнении к написанию и редактированию книг, руководств пользователей и документации, он работает в широком спектре интересов, связанных с компьютерами и компьютерными базами данных.</li>
</ul>
<h2 id="глава-1-введение-в-реляционную-базу-данных">Глава 1. ВВЕДЕНИЕ В РЕЛЯЦИОННУЮ БАЗУ ДАННЫХ</h2>
<p>SQL (ОБЫЧНО ПРОИЗНОСИМАЯ КАК &quot;SEEQUEL&quot; [&quot;СЭКВЭЛ&quot;]) символизирует собой Структурированный Язык Запросов. Это - язык который дает вам возможностьсоздавать и работать в реляционных базах данных, которые являются наборами связанной информации сохраняемой в таблицах.
Мир баз данных становится все более и более единым, что привело к необходимости создания стандартного языка который мог бы использоваться чтобы функционировать в большом количестве различных видов компьютерных сред. Стандартный язык позволит пользователям знающим один набор команд, использовать их чтобы создавать, отыскивать, изменять, и передавать информацию независимо от того работают ли они на персональном компьютере, сетевой рабочей станции, или на универсальной ЭВМ.
В нашем все более и более взаимосвязанном компьютерном мире, пользователь снабженый таким языком, имеет огромное преимущество в использовании и обобщении информации из ряда источников с помощью большого колличества способов.
Элегантность и независимость от специфики компьютерных технологий, а также его поддержка лидерами промышленности в области технологии реляционных баз данных, сделало SQL, и вероятно в течение обозримого будущего оставит его, основным стандартным языком. По этой причине, любой кто хочет работать с базами данных 90-х годов должен знать SQL.
Стандарт SQL определяется ANSI (Американским Национальным Институтом Стандартов) и в данное время также принимается ISO (МЕЖДУНАРОДНОЙ ОРГАНИЗАЦИЕЙ ПО СТАНДАРТИЗАЦИИ). Однако, большинство коммерческих программ баз данных расширяют SQL без уведомления ANSI, добавляя разные другие особенности в этот язык, которые, как они считают, будут весьма полезны. Иногда они несколько нарушают стандарт языка, хотя хорошие идеи имеют тенденцию развиваться и вскоре становиться стандартами &quot;рынка&quot; сами по себе в силу полезности своих качеств. В этой книге, мы будем, в основном, следовать стандарту ANSI, но одновременно иногда будет показывать и некоторые наиболее общие отклонения от его стандарта.
Вы должны проконсультироваться с документацией вашего пакета программ который вы будете использовать, чтобы знать где в нем этот стандарт видоизменен. ПРЕЖДЕ, ЧЕМ ВЫ СМОЖЕТЕ ИСПОЛЬЗОВАТЬ SQL, ВЫ должны понять что такое реляционные базы данных. В этой главе, мы это объясним, и покажем насколько реляционные базы данных полезны. Мы не будем обсуждать SQL именно здесь, и если вы уже знаете эти понятия довольно хорошо, вы можете просто пропустить эту главу. В любом случае, вы должны рассмотреть три таблицы которые предоставляются и объясняются в конце главы; они станут основой наших примеров в этой книге. Вторая копия этих таблиц находится Приложении E, и мы рекомендуем скопировать их для удобства ссылки к ним.
ЧТО ТАКОЕ - РЕЛЯЦИОННАЯ БАЗА ДАННЫХ?
Реляционная база данных - это тело связанной информации, сохраняемой в двумерных таблицах. Напоминает адресную или телефонную книгу. В книге имеется большое количество входов, каждый из которых соответствует определеной особенности. Для каждой такой особенности, может быть несколько независимых фрагментов данных, например имя, телефонный номер, и адрес. Предположим, что вы должны сформатировать эту адресную книгу в виде таблицы со строками и столбцами. Каждая строка (называемая также записью ) будет соответствовать определенной особенности; каждый столбец будет содержать значение для каждого типа данных - имени, телефонного номера, и адреса представляемого в каждой строке. Адресная книга могла бы выглядеть следующим образом:</p>
<table>
<thead>
<tr>
<th>   Имя</th>
<th>   Телефон</th>
<th>   Адрес</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Gerry Farish<br style="margin: 0px; padding: 0px;"></td>
<td>   ( 415)365-8775 127<br style="margin: 0px; padding: 0px;"></td>
<td>   Primrose Ave.,SF<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Celia Brock<br style="margin: 0px; padding: 0px;"></td>
<td>   ( 707)874-3553 246<br style="margin: 0px; padding: 0px;"></td>
<td>   #3rd St.,Sonoma<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Yves Grillet<br style="margin: 0px; padding: 0px;"></td>
<td>   ( 762)976-3665<br style="margin: 0px; padding: 0px;"></td>
<td>   778 Modernas,Barcelona<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>То что вы получили является основой реляционной базы данных как и было определено в начале этого обсуждения - а именно, двумерной (строка и столбец ) таблицей информации. Однако, реляционные базы данных редко состоят из одной таблицы. Такая таблица меньше чем файловая система. Создав несколько таблиц взаимосвязанной информации, вы сможете выполнить более сложные и мощные операции с вашими данными. Мощность базы данных зависит от связи которую вы можете создать между фрагментами информации, а не от самого фрагмента информации.</p>
<h3 id="связывание-одной-таблицы-с-другой">СВЯЗЫВАНИЕ ОДНОЙ ТАБЛИЦЫ С ДРУГОЙ</h3>
<p>Позвольте нам использовать пример нашей адресной книги чтобы начать обсуждение базы данных которая может реально использоваться в деловой ситуации. Предположим, что персонажи в нашей первой таблице (адресной книги ) - это пациенты больницы. В другой таблице, мы могли бы запомнить дополнительную информацию об этих пациентах. Столбцы второй таблицы могли бы быть помечены как Пациент, Доктор, Страховка, и Балланс.</p>
<table>
<thead>
<tr>
<th>   Пациент</th>
<th>   Доктор</th>
<th>   Страховка</th>
<th>   Балланс</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Farish<br style="margin: 0px; padding: 0px;"></td>
<td>   Drume<br style="margin: 0px; padding: 0px;"></td>
<td>   B.C./B.S.<br style="margin: 0px; padding: 0px;"></td>
<td>   $272.99<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Grillet<br style="margin: 0px; padding: 0px;"></td>
<td>   Halben<br style="margin: 0px; padding: 0px;"></td>
<td>   None<br style="margin: 0px; padding: 0px;"></td>
<td>   $44. 76<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Brock<br style="margin: 0px; padding: 0px;"></td>
<td>   Halben<br style="margin: 0px; padding: 0px;"></td>
<td>   Health,Inc.<br style="margin: 0px; padding: 0px;"></td>
<td>   $9077.47<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Много мощных функций можно выполнить извлекая информацию из этих таблиц согласно указанным параметрам, особенно когда эти параметры включают в себя фрагменты информации свзанные в различных таблицах друг с другом. Например, возьмем - докторов. Предположим доктор Halben захотел получить номера телефонов всех своих пациентов. Чтобы извлечь эту информацию, он мог бы связать таблицу с номерами телефонов пациентов (по адресной книге ) с таблицей которая бы указывала, какой из пациентов - его. Хотя, в этом простом примере, он мог бы держать это в голове и сразу получать номера телефонов пациентов Grillet и Brock, эти таблицы могут быть слишком большими и слишком сложными. Программы реляционной базы данных разрабатывались для того чтобы обрабатывать большие и сложные совокупности данных такого типа, что очевидно является более универсальным методом в деловом мире. Даже если бы база данных больницы содержала сотни или тысячи имен - как это вероятно и бывает на практике - одна команда SQL могла бы выдать доктору Halben информацию в которой он нуждался почти немедленно.</p>
<h3 id="порядок-строк-произволен">ПОРЯДОК СТРОК ПРОИЗВОЛЕН</h3>
<p>Чтобы поддерживать максимальную гибкость, строки таблицы, по определению, не должны находиться ни в каком определенном порядке. С этой точки зрения, в этом структура базы данных отличается от нашей адресной книги. Вход в адресную книгу обычно упорядочивается в алфавитном порядке. В системах с реляционной базой данных, имеется одна мощная возможность для пользоватей - это способность упорядочивать информацию так чтобы они могли восстанавливать ее.
Рассмотрим вторую таблицу. Иногда Вам необходимо видеть эту информацию упорядоченной в алфавитном порядке по именам, иногда в возрастающем или убывающем порядке, а иногда сгруппированной по отношению к какому-нибудь доктору. Наложение порядка набора в строках будет сталкиваться со способностью заказчика изменять его, поэтому строки всегда рассматриваются как неупорядоченные. По этой причине, вы не можете просто сказать:&quot; Мы хотим посмотреть пятую строку таблицы. &quot; Пренебрегая порядком в котором данные вводились или любым другим критерием, мы определим, не ту строку, хотя она и будет пятой. Строки таблицы которые рассматриваются, не будут в какой-либо определенной последовательности.</p>
<h3 id="идентификация-строк-первичные-ключи-">ИДЕНТИФИКАЦИЯ СТРОК (ПЕРВИЧНЫЕ КЛЮЧИ )</h3>
<p>По этим и другим причинам, вы должны иметь столбец в вашей таблице который бы уникально идентифицировал каждую строку. Обычно, этот столбец содержит номер - например, номер пациента назначаемый каждому пациенту. Конечно, вы могли бы использовать имя пациентов, но возможно что имеется несколько Mary Smiths; и в этом случае, вы не будете иметь другого способа чтобы отличить этих пациентов друг от друга.
Вот почему номера так необходимы. Такой уникальный столбец( или уникальная группа столбцов ), используемый чтобы идентифицировать каждую строку и храненить все строки отдельно, называются - первичными ключами таблицы.
Первичные ключи таблицы важный элемент в структуре базы данных. Они - основа вашей системы записи в файл; и когда вы хотите найти определенную строку в таблице, вы ссылаетесь к этому первичному ключу. Кроме того, первичные ключи гарантируют, что ваши данные имеют определенную целостность. Если первичный ключ правильно используется и поддерживается, вы будете знать что нет пустых строк таблицы и что каждая строка отличается от любой другой строки. Мы будем обсуждать ключи и далее когда поговорим относительно справочной целостности в Главе 19.</p>
<h3 id="столбцы-именуются-и-нумеруются">СТОЛБЦЫ ИМЕНУЮТСЯ И НУМЕРУЮТСЯ</h3>
<p>В отличие от строк, столбцы таблицы (также называемые полями ) упорядочиваются и именуются. Таким образом, в нашей таблице адресной книги, возможно указать на &quot; адрес столбца &quot; или на &quot; столбец 3 &quot;. Конечно, это означает что каждый столбец данной таблицы должен иметь уникальное имя чтобы избежать неоднозначности. Лучше всего если эти имена указывают на содержание поля. В типовых таблицах этой книги, мы будем использовать такие сокращения для имени столбца, как cname для имени заказчика, и odate для даты порядка. Мы также дадим каждой таблице личный числовой номер столбца в качестве первичного ключа. Следующий раздел будет объяснять эти таблицы и их ключи более подробно.</p>
<h3 id="типовая-база-данных">ТИПОВАЯ БАЗА ДАННЫХ</h3>
<p>Таблицы 1.1, 1.2, и 1.3 составляют реляционную базу данных которая является минимально достаточной чтобы легко ее отслеживать, и достаточно полной, чтобы иллюстрировать главные понятия и практику использования SQL.
Эти таблицы напечатаны в этой главе а также в Приложении E. Так как они будут использоваться для иллюстрирования различных особенностей SQL по всей этой книге, мы рекомендуем чтобы вы скопировали их, для удобства ссылки к ним.
Вы могли уже обратить внимание что первый столбец каждой таблицы содержит номера чьи значения различны для каждой строки. Как вы наверное и предположили, это - первичные ключи таблиц. Некоторые из этих номеров также показаны в столбцах других таблиц. В этом нет ничего неверного. Они поазывают связь между строками которые используют значение принимаемое из первичного ключа, и строками где это значение используется в самом первичном ключе.</p>
<p>Таблица 1.1: Продавцы</p>
<table>
<thead>
<tr>
<th>   SNUM</th>
<th>   SNAME</th>
<th>   CITY</th>
<th>   COMM</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   .12<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   .13<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   .11<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   .15<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   .10<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 1.2: Заказчики</p>
<table>
<thead>
<tr>
<th>   CNUM</th>
<th>   CNAME</th>
<th>    CITY</th>
<th>   RATING</th>
<th>   SNUM</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   Giovanni<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   200<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2003<br style="margin: 0px; padding: 0px;"></td>
<td>   Liu<br style="margin: 0px; padding: 0px;"></td>
<td>   SanJose<br style="margin: 0px; padding: 0px;"></td>
<td>   200<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   Grass<br style="margin: 0px; padding: 0px;"></td>
<td>   Berlin<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
<td>   SanJose<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 1.3: Порядки</p>
<table>
<thead>
<tr>
<th>   ONUM</th>
<th>   AMT</th>
<th>   ODATE</th>
<th>   CNUM</th>
<th>   SNUM</th>
</tr>
</thead>
<tbody>
<tr>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   18.69<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3003<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3002<br style="margin: 0px; padding: 0px;"></td>
<td>   1900.10<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3005<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2003<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3006<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3008<br style="margin: 0px; padding: 0px;"></td>
<td>   4723.00<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3011<br style="margin: 0px; padding: 0px;"></td>
<td>   9891.88<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Например, поле snum в таблице Заказчиков указывает, какому продавцу назначен данный заказчик. Номер поля snum связан с таблицей Продавцов, которая дает информацию об этих продавцах. Очевидно, что продавец которому назначены заказчики должен уже существовать - то есть, значение snum из таблицы Заказчиков должно также быть представлено в таблице Продавцов. Если это так, то говорят, что &quot;система находится в состоянии справочной целостности &quot;.</p>
<p>Этот вывод будет более полно и формально объяснен в Главе 19.
ПРИМЕЧАНИЕ: Эти три представленых таблицы в тексте имеют русские имена - Продавцов, Заказчиков и Порядков, и далее будут упоминаться именно под этими именами. Имена любых других применяемых в книге таблиц будут написаны по английски что бы отличать их от наших базовых таблиц этой базы данных. Кроме того в целях однозначности, имена заказчиков, продавцов, Системных Каталогов а также полей в тексте, также будут даны на латыни.
Таблицы приведены как пример к похожей ситуации в реальной жизни, когда вы будете использовать SQL чтобы следить за продавцами, их заказчиками, и порядками заказчиков. Давайте рассмотрим эти три таблицы и значения их полей.</p>
<p>Здесь показаны столбцы Таблицы 1.1</p>
<table>
<thead>
<tr>
<th>   ПОЛЕ</th>
<th>   СОДЕРЖАНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   snum<br style="margin: 0px; padding: 0px;"></td>
<td>   уникальный номер назначенный каждому продавцу<br style="margin: 0px; padding: 0px;">   ( &quot; номер служащего &quot; ).<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   sname<br style="margin: 0px; padding: 0px;"></td>
<td>   имя продавца.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   city<br style="margin: 0px; padding: 0px;"></td>
<td>   расположение продавца( город )<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   comm<br style="margin: 0px; padding: 0px;"></td>
<td>   комиссионные продавцов в десятичной форме<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 1.2 содержит следующие столбцы:</p>
<table>
<thead>
<tr>
<th>   ПОЛЕ</th>
<th>   СОДЕРЖАНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   cnum<br style="margin: 0px; padding: 0px;"></td>
<td>   уникальный номер назначенный каждому заказчику<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   cname<br style="margin: 0px; padding: 0px;"></td>
<td>   имя заказчика<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   city<br style="margin: 0px; padding: 0px;"></td>
<td>   расположение заказчика( город )<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   rating<br style="margin: 0px; padding: 0px;"></td>
<td>   код указывающего уровень предпочтения данного заказчика<br style="margin: 0px; padding: 0px;">   перед другими. Более высокий номер указывают на большее<br style="margin: 0px; padding: 0px;">   предпочтение( рейтинг )<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   snum<br style="margin: 0px; padding: 0px;"></td>
<td>   номер продавца назначенного этому заказчику<br style="margin: 0px; padding: 0px;">   ( из таблицы Продавцов )<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>И имеются столбцы в Таблице 1.3:</p>
<table>
<thead>
<tr>
<th>   ПОЛЕ</th>
<th>   СОДЕРЖАНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   onum<br style="margin: 0px; padding: 0px;"></td>
<td>   уникальный номер данный каждому приобретению<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   amt<br style="margin: 0px; padding: 0px;"></td>
<td>   значение суммы приобретений<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   odate<br style="margin: 0px; padding: 0px;"></td>
<td>   дата приобретения<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   cnum<br style="margin: 0px; padding: 0px;"></td>
<td>   номер заказчика делающего приобретение<br style="margin: 0px; padding: 0px;">   ( из таблицы Заказчиков )<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   snum<br style="margin: 0px; padding: 0px;"></td>
<td>   номер продавца продающего приобретение<br style="margin: 0px; padding: 0px;">   ( из таблицы Продавцов)<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<h3 id="резюме">РЕЗЮМЕ</h3>
<p>Теперь вы знаете что такое реляционная база данных, понятие, которое звучит сложнее чем есть на самом деле. Вы также изучили некоторые фундаментальные принципы относительно того, как сделаны таблицы - как работают строки и столбцы, как первичные ключи отличают строки друга друга, и как столбцы могут ссылаться к значениям в других столбцах.
Вы поняли что запись это синоним строки, и что поле это синоним столбца. Оба термина встречаются в обсуждении SQL, и мы будем использовать их в равной степени в этой книге.</p>
<h2 id="глава-2-sql--обзор">Глава 2. SQL : ОБЗОР.</h2>
<p>ЭТА ГЛАВА ПОЗАКОМИТ ВАС СО СТРУКТУРОЙ SQL языка а также с определенными общими выводами, такими как тип данных которые эти поля могут содержать и некоторые области неоднозначностей которые существуют в SQL.
Она педназначена обеспечить связь с более конкретной информацией в последующих главах. Вы не должны запоминать каждую подробность упомянутую в этой главе. Краткий обзор представлен здесь в одной удобно размещеной области, многие подробности которой вы можете иметь чтобы в последствии ссылаться к ним по мере овладения языком. Мы поместили все это в начало книги чтобы ориентировать вас на мир SQL без упрощенного подхода к его проблемам и в тоже время дать Вам привычные в будущем места для ссылки к ним когда у Вас появятся вопросы. Этот материал может стать более понятным когда мы перейдем к описанию конкретных команд SQL, начинающихся с Главы 3.</p>
<h3 id="как-работает-sql">КАК РАБОТАЕТ SQL?</h3>
<p>SQL это язык ориентированный специально на реляционные базы данных.
Он устраняет много работы которую вы должны были бы сделать если бы вы использовали универсальный язык программирования, напрмер C. Чтобы сформировать реляционную базу данных на C, вам необходимо было бы начать с самого начала. Вы должны были бы определить объект - называемый таблицей которая могла бы расти чтобы иметь любое число строк, а затем создавать постепенно процедуры для помещения значений в нее и извлечения из них. Если бы вы захотели найти некоторые определенные строки, вам необходимо было бы выполнить по шагам процедуру, подобную следующей :</p>
<ul>
<li>Рассмотрите строку таблицы.</li>
<li>Выполните проверку - является ли эта строка одной из строк которая вам нужна.</li>
<li>Если это так, сохраните ее где-нибудь пока вся таблица не будет проверена.</li>
<li>Проверьте имеются ли другие строки в таблице.</li>
<li>Если имеются, возвратитесь на шаг 1.</li>
<li>Если строк больше нет, вывести все значения сохраненные в шаге 3.</li>
</ul>
<p>( Конечно, это не фактический набор C команд, а только логика шагов которые должны были бы быть включены в реальную программу.) SQL сэкономит вам все это. Команды в SQL могут работать со всеми группами таблиц как с единым объектом и могут обрабатывать любое количество информации извлеченной или полученной из их, в виде единого модуля.</p>
<h3 id="что-делает-ansi">ЧТО ДЕЛАЕТ ANSI?</h3>
<p>Как мы уже рассказывали в Введении, стандарт SQL определяется с помощью кода ANSI (Американский Национальный Институт Стандартов). ANSI не изобретал SQL. Это по существу изобретение IBM. Но другие компании подхватили SQL сразу же, по крайней мере одна компания (Oracle) отбила у IBM право на рыночную продажу SQL продуктов.
После того как появился ряд конкурирующих программ SQL на рынке, ANSI определил стандарт к которому они должны быть приведены (определение таких стандартов и является функцией ANSI ).
Однако после этого, появились некоторые проблемы. Возникли они в результате стандартизации ANSI ввиде некоторых ограничений. Так как не всегда ANSI определяет то что является наиболее полезным, то программы пытаются соответствовать стандарту ANSI не позволяя ему ограничивать их слишком сильно. Это, в свою очередь, ведет к случайным несогласованностям. Программы Баз Данных обычно дают ANSI SQL дополнительные особенности и часто ослабляют многие ограничения из большинства из них.
Следовательно, общие разновидности ANSI будут также рассмотрены. Хотя мы очевидно не сможем объять каждое исключение или разновидность, удачные идеи имеют тенденцию к внедрению и использованию в различных программах даже когда они не определены стандартом ANSI.
ANSI - это вид минимального стандарта и вы можете делать больше чем он позволяет, хотя и должны выполнять его указания при выполнении задач которые он определяет.</p>
<h3 id="интерактивный-и-вложенный-sql">ИНТЕРАКТИВНЫЙ И ВЛОЖЕННЫЙ SQL</h3>
<p>Имеются два SQL: Интерактивный и Вложенный. Большей частью, обе формы работают одинаково, но используются различно. Интерактивный SQL используется для функционирования непосредственно в базе данных чтобы производить вывод для использования его заказчиком. В этой форме SQL, когда вы введете команду, она сейчас же выполнится и вы сможете увидеть вывод (если он вообще получится) - немедленно.
Вложенный SQL состоит из команд SQL помещенных внутри программ, которые обычно написаны на некотором другом языке (типа КОБОЛА или Паскаля).
Это делает эти программы более мощными и эффективным. Однако, допуская эти языки, приходится иметь дело с структурой SQL и стилем управления данных который требует некоторых расширений к интерактивному SQL. Передача SQL команд во вложенный SQL является выдаваемой (&quot;passed off&quot;) для переменных или параметров используемых программой в которую они были вложены.
В этой книге, мы будем представлять SQL в интерактивной форме. Это даст нам возможность обсуждать команды и их эффекты не заботясь о том как они связаны с помощью интерфейса с другими языками. Интерактивный SQL - это форма наиболее полезная непрограммистам. Все что вы узнаете относительно интерактивного SQL в основном применимо и к вложенной форме. Изменения необходимые для использования вложенной формы будут использованы в последней главе этой книги.</p>
<h3 id="субподразделения-sql">СУБПОДРАЗДЕЛЕНИЯ SQL</h3>
<p>И в интерактивной и во вложенной формах SQL, имеются многочисленные части, или субподразделения. Так как вы вероятно сталкнетесь с этой терминологией при чтении SQL, мы дадим некоторые пояснения.
К сожалению, эти термины не используются повсеместно во всех реализациях. Они подчеркиваются ANSI и полезны на концептуальном уровне, но большинство SQL программ практически не обрабатывают их отдельно, так что они по существу становятся функциональными категориями команд SQL.
DDL (Язык Определения Данных ) - так называемый Язык Описания Схемы в ANSI, состоит из команд которые создают объекты (таблицы, индексы, просмотры, и так далее ) в базе данных.
DML (Язык Манипулирования Данными) - это набор команд которые определяют какие значения представлены в таблицах в любой момент времени.
DCD (Язык Управления Данными) состоит из средств которые определяют, разрешить ли пользователю выполнять определенные действия или нет.
Они являются составными частями DDL в ANSI. Не забывайте эти имена.
Это не различные языки, а разделы команд SQL сгруппированных по их функциям.</p>
<h3 id="различные-типы-данных">РАЗЛИЧНЫЕ ТИПЫ ДАННЫХ</h3>
<p>Не все типы значений которые могут занимать поля таблицы - логически одинаковые. Наиболее очевидное различие - между числами и текстом. Вы не можете помещать числа в алфавитном порядке или вычитать одно имя из другого. Так как системы с реляционной базой данных базируются на связях между фрагментами информации, различные типы данных должны понятно отличаться друга от друга, так чтобы соответствующие процессы и срав нения. могли быть в них выполнены.
В SQL, это делается с помощью назначения каждому полю - типа данных который укаазывает на тип значения которое это поле может содержать.
Все значения в данном поле должны иметь одинаковый тип. В таблице Заказчиков, например, cname и city - содержат строки текста для оценки, snum, и cnum - это уже номера. По этой причине, вы не можете ввести значение Highest(Наивысший) или значение None(Никакой) в поле rating, которое имеет числовой тип данных. Это ограничение удачно, так как оно налагает некоторую структурность на ваши данные. Вы часто будете сравнивать некоторые или все значения в данном поле, поэтому вы можете выполнять действие только на определенных строках а не на всех. Вы не могли бы сделать этого если бы значения полей имели смешанный тип данных.
К сожалению, определение этих типов данных является основной областью в которой большинство коммерческих программ баз данных и официальный стандарт SQL, не всегда совпадают. ANSI SQL стандарт распознает только текст и тип номера, в то время как большинство коммерческих программ используют другие специальные типы. Такие как, DATA(ДАТА) и TIME(ВРЕМЯ) - фактически почти стандартные типы( хотя точный формат их меняется). Некоторые пакеты также поддерживают такие типы, как например MONEY(ДЕНЬГИ) и BINARY (ДВОИЧНЫЕ). (MONEY - это специальная система исчисления используемая компьютерами. Вся информация в компьютере передается двоичными числами и затем преобразовываются в другие системы, что бы мы могли легко использовать их и понимать.)
ANSI определяет несколько различных типов значений чисел, различия между которыми - довольно тонки и иногда их путают. Разрешенные ANSI типы данных перечислены в Приложении B.
Сложность числовых типов ANSI можно, по крайней мере частично,объяснить усилием сделать вложенный SQL, совместимым с рядом других языков.
Два типа чисел ANSI, INTEGER(ЦЕЛОЕ ЧИСЛО) и DECIMAL (ДЕСЯТИЧНОЕ ЧИСЛО) (которые можно сокращать как INT и DEC, соответственно ), будут адекватны для наших целей, также как и для целей большинства практических деловых прикладных программ. Естественно, что тип ЦЕЛОЕ можно представить как ДЕСЯТИЧНОЕ ЧИСЛО которое не содержит никаких цифр справа от десятичной точки.
Тип для текста - CHAR (или СИМВОЛ ), который относится к строке текста. Поле типа CHAR имеет определенную длину, которая определяется максимальным числом символов которые могут быть введены в это поле.
Больше всего реализаций также имеют нестандартный тип называемый VARCHAR(ПЕРЕМЕННОЕ ЧИСЛО СИМВОЛОВ), который является текстовой строкой которая может иметь любую длину до определенного реализацией максимума (обычно 254 символа). CHARACTER и VARCHAR значения включаются в одиночные кавычки как &quot;текст&quot;. Различие между CHAR и VARCHAR в том, что CHAR должен резервировать достаточное количество памяти для максимальной длины строки, а VARCHAR распределяет память так как это необходимо.
Символьные типы состоят из всех печатных символов, включая числа.
Однако, номер 1 не то же что символ &quot;1&quot;. Символ &quot;1&quot; - только другой печатный фрагмент текста, не определяемый системой как наличие числового значения 1.
Например 1 + 1=2, но &quot;1&quot; + &quot;1&quot; не равняется &quot;2&quot;.
Символьные значения сохраняются в компьютере как двоичные значения, но показываются пользователю как печатный текст. Преобразование следует за форматом определяемым системой которую вы используете. Этот формат преобразования будет одним из двух стандартных типов (возможно с расширениями) используемых в компьютерных системах: в ASCII коде (используемом во всех персональных и малых компьютерах ) и EBCDIC коде (Расширенном Двоично-Десятичном Коде Объмена Информации) (используемом в больших компьютерах). Определенные операции, такие как упорядочивание в алфавитном порядке значений поля, будет изменяться вместе с форматом. Применение этих двух форматов будет обсуждаться в Главе 4.
Мы должны следить за рынком, а не ANSI, в использовании типа называемого DATE(ДАТОЙ). (В системе, которая не распознает тип ДАТА, вы конечно можете обьявить дату как символьное или числовое поле, но это сделает большинство операций более трудоемкими. ) Вы должны смотреть свою документацию по пакету программ которые вы будете использовать, чтобы выяснить точно, какие типы данных она поддерживает.</p>
<h3 id="sql-несогласованности">SQL НЕСОГЛАСОВАННОСТИ</h3>
<p>Вы можете понять из предшествующего обсуждения, что имеются самостоятельные несогласованности внутри продуктов мира SQL. SQL появился из коммерческого мира баз данных как инструмент, и был позже превращен в стандарт ANSI. К сожалению, ANSI не всегда определяет наибольшую пользу, поэтому программы пытаются соответствовать стандарту ANSI не позволяя ему ограничивать их слишком сильно. ANSI - вид минимального стандарта - вы можете делать больше чем он это позволяет, но вы должны быть способны получить те же самые результаты что и при выполнении той же самой задачи.</p>
<h3 id="что-такое---пользователь">ЧТО ТАКОЕ - ПОЛЬЗОВАТЕЛЬ?</h3>
<p>SQL обычно находится в компьютерных системах которые имеют больше чем одного пользователя, и следовательно должны делать различие между ними (ваше семейство PC может иметь любое число пользователей, но оно обычно не имеет способов чтобы отличвать одного от другого). Обычно, в такой системе, каждый пользователь имеет некий вид кода проверки прав который идентифицирует его или ее (терминология изменяется). В начале сеанса с компьютером, пользователь входит в систему (регистрируется), сообщая компьютеру кто этот пользователь, идентифицированный с помощью определенного ID(Идентификатора). Любое колличество людей использующих тот же самый ID доступа, являются отдельными пользователями; и аналогично, один человек может представлять большое количество пользователей (в разное время ), используя различные доступные Идентификаторы.
SQL следует этому примеру. Действия в большинстве сред SQL приведены к специальному доступному Идентификатору который точно соответствует определенному пользователю. Таблица или другой объект принадлежит пользователю, который имеет над ним полную власть. Пользователь может или не может иметь привилегии чтобы выполнять действие над объектом.
Для наших целей, мы договоримся, что любой пользователь имеет привилегии необходимые чтобы выполнять любое действие, пока мы не возвратимся специально к обсуждению привилегий в Главе 22.
Специальное значение - USER(ПОЛЬЗОВАТЕЛЬ) может использоваться как аргумент в команде. Оно указывает на доступный Идентификатор пользователя, выдавшего команду.</p>
<h3 id="условия-и-терминология">УСЛОВИЯ И ТЕРМИНОЛОГИЯ</h3>
<p>Ключевые слова - это слова которые имеют специальное значение в SQL. Они могут быть командами, но не текстом и не именами объектов. Мы будем выделять ключевые слова печатая их ЗАГЛАВНЫМИ БУКВАМИ. Вы должны соблюдать осторожность чтобы не путать ключевые слова с терминами.
SQL имеет определенные специальные термины которые используются чтобы описывать его. Среди них - такие слова как запрос, предложение, и предикат, которые являются важнейшими в описании и понимании языка но не означают что-нибудь самостоятельное для SQL.
Команды, или предложения, являются инструкциями которыми Вы обращаетесь к SQL базе данных. Команды состоят из одной или более отдельных логических частей называемых предложениями. Предложения начинаются ключевым словом для которого они являются проименованными, и состоят из ключевых слов и аргументов. Например предложения с которыми вы можете сталкиваться - это &quot; FROM Salespeope &quot; и &quot; WHERE city=&quot;London&quot;.
Аргументы завершают или изменяют значение предложения. В примерах выше, Salespeople - аргумент, а FROM - ключевое слово предложения FROM.
Аналогично, &quot; city=&quot;London&quot; &quot; - агрумент предложения WHERE. Объекты - структуры в базе данных которым даны имена и сохраняются в памяти.
Они включают в себя базовые таблицы, представления (два типа таблиц), и индексы.
Чтобы показать Вам как формируются команды, мы будем делать это на примерах. Имеется, однако, более формальный метод описания команд использующих стандартизированные условные обозначения. Мы будем использовать его в более поздних главах, для удобства чтобы понимать эти условные обозначения в случае если вы столкнетесь с ним в других SQL документах. Квадратные скобки ([ ] ) будут указывать части которые могут неиспользоваться, а многоточия (... ) указывать что все предшествующее им может повторяться любое число раз. Слова обозначенные в угловых скобках (&lt;&gt;) - специальные термины которые объясняют что они собой представляют.
Мы упростили стандартную терминологию SQL значительно, но без ухудшения его понимания.</p>
<h3 id="резюме-1">РЕЗЮМЕ</h3>
<p>Мы быстро прошли основы в этой главе. Но нашим намерением и было - просто пролететь над основами SQL, так чтобы вы могли понять идею относительно всего объема. Когда мы возвратимся к основе в следующей главе, некоторые вещи станут более конкретными. Теперь вы знаете кое-что относительно SQL - какова его структура, как он используется, как он представляет данные, и как они определяются (и некоторые несогласованности появляющиеся при этом ), и некоторые условные обозначения и термины используемые чтобы описывать их. Все это - много информации для одной главы; мы не ожидаем что бы вы запомнили все эти подробности, но вы сможете вернуться позже к ним если понадобится. По Главе 3, мы будем идти, показывая конкретно, как формируются команды и что они делают. Мы представим вам команду SQL используемую чтобы извлекать информацию из таблиц, и которая является наиболее широко используемой командой в SQL. К концу этой главы, вы будете способны извлекать конкретную информацию из вашей базы данных с высокой степенью точности.</p>
<h2 id="глава-3-использование-sql-для-извлечения-информации-из-таблиц">Глава 3. ИСПОЛЬЗОВАНИЕ SQL ДЛЯ ИЗВЛЕЧЕНИЯ ИНФОРМАЦИИ ИЗ ТАБЛИЦ.</h2>
<p>В ЭТОЙ ГЛАВЕ МЫ ПОКАЖЕМ ВАМ КАК ИЗВЛЕКАТЬ информацию из таблиц. Вы узнаете как опускать или переупорядочивать столбцы и как автоматически устранять избыточность данных из вашего вывода. В заключение, вы узнаете как устанавливать условие( проверку ) которую вы можете использовать чтобы определить какие строки таблицы используются в выводе. Эта последняя особенность, будет далее описана в более поздних главах и является одной из наиболее изящных и мощных в SQL.</p>
<h3 id="создание-запроса">СОЗДАНИЕ ЗАПРОСА</h3>
<p>Как мы подчеркивали ранее, SQL символизирует собой Структурированный Язык Запросов. Запросы - вероятно наиболее часто используемый аспект SQL. Фактически, для категории SQL пользователей, маловероятно чтобы кто-либо использовал этот язык для чего-то друго. По этой причине, мы будем начинать наше обсуждение SQL с обсуждения запроса и как он выполняется на этом языке.</p>
<h3 id="что-такое-запрос">ЧТО ТАКОЕ ЗАПРОС?</h3>
<p>Запрос - команда которую вы даете вашей программе базы данных, и которая сообщает ей чтобы она вывела определенную информацию из таблиц в память. Эта информация обычно посылается непосредственно на экран компьютера или терминала которым вы пользуетесь, хотя, в большинстве случаев, ее можно также послать принтеру, сохранить в файле (как объект в памяти компьютера ), или представить как вводную информацию для другой команды или процесса.</p>
<h3 id="где-применяются-запросы">ГДЕ ПРИМЕНЯЮТСЯ ЗАПРОСЫ?</h3>
<p>Запросы обычно рассматриваются как часть языка DML. Однако, так как запрос не меняет информацию в таблицах, а просто показывает ее пользователю, мы будем рассматривать запросы как самостоятельную категорию среди команд DML которые производят действие, а не просто показывают содержание базы данных.
Все запросы в SQL состоят из одиночной команды. Структура этой команды обманчиво проста, потому что вы должны расширять ее так чтобы выполнить высоко сложные оценки и обработки данных. Эта команда называется - SELECT(ВЫБОР).</p>
<h3 id="команда-select-1">КОМАНДА SELECT</h3>
<p>В самой простой форме, команда SELECT просто инструктирует базу данных чтобы извлечь информацию из таблицы. Например, вы могли бы вывести таблицу Продавцов напечатав следующее:</p>
<p>SELECT snum, sname, sity, comm
FROM Salespeople;
Вывод для этого запроса показывается в таблице 3.1.</p>
<h3 id="sql-execution-log">SQL Execution Log</h3>
<pre><code>SELECT snum, sname, sity, comm FROM Salespeople;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.12<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   0.13<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.11<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   0.15<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   0.10<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 3.1: команда SELECT</p>
<p>Другими словами, эта команда просто выводит все данные из таблицы. Большинство программ будут также давать заголовки столбца как выше, а некоторые позволяют детальное форматирование вывода, но это уже вне стандартной спецификации.
Имеется объяснение каждой части этой команды:
<strong>SELECT</strong> Ключевое слово которое сообщает базе данных что эта команда - запрос. Все запросы начинаются этим словом, сопровождаемым пробелом.
snum, sname Это - список столбцов из таблицы которые выбираются запросом. Любые столбцы не перечисленные здесь не будут включены в вывод команды. Это, конечно, не значит что они будут удалены или их информация будет стерта из таблиц, потому что запрос не воздействует на информацию в таблицах; он только показывает данные.
<strong>FROM FROM</strong> - ключевое слово, подобно <strong>SELECT</strong>, которое должно Salespeople быть представлено в каждом запросе. Оно сопровождается пробелом и затем именем таблицы используемой в качестве источника информации. В данном случае - это таблица Продавцов(Salespeople).
Точка с запятой используется во всех интерактивных командах SQL чтобы сообщать базе данных что команда заполнена и готова выполниться.
В некоторых системах наклонная черта влево () в строке, является индикатором конца команды.
Естественно, запрос такого характера не обязательно будет упорядочивать вывод любым указаным способом. Та же самая команда выполненная с теми же самыми данными но в разное время не сможет вывести тот же самый порядок. Обычно, строки обнаруживаются в том порядке в котором они найдены в таблице, поскольку как мы установили в предыдущей главе - этот порядок произволен. Это не обязательно будет тот порядок в котором данные вводились или сохранялись. Вы можете упорядочивать вывод командами SQL непосредственно: с помощью специального предложения.
Позже, мы покажем как это делается. А сейчас, просто усвойте, что в отсутствии явного упорядочения, нет никакого определенного порядка в вашем выводе.
Наше использование возврата (Клавиша ENTER ) является произвольным. Мы должны точно установить как удобнее составить запрос, в несколько строк или в одну строку, следующим образом:</p>
<pre><code>SELECT snum, sname, city, comm FROM Salespeople;
</code></pre>
<p>С тех пор как SQL использует точку с запятой чтобы указывать конец команды, большинство программ SQL обрабатывают возврат (через нажим Возврат или клавишу ENTER ) как пробел. Это - хорошая идея чтобы использовать возвраты и выравнивание что мы делали это ранее, чтобы сделать ваши команды более легкими для чтения и более правильными.</p>
<h3 id="выбирайте-всегда-самый-простой-способ">ВЫБИРАЙТЕ ВСЕГДА САМЫЙ ПРОСТОЙ СПОСОБ</h3>
<p>Если вы хотите видеть каждый столбец таблицы, имеется необязательное сокращение которое вы можете использовать. Звездочка (*) может применяться для вывода полного списка столбцов следующим образом:</p>
<pre><code>SELECT *
FROM Salespeople;
</code></pre>
<p>Это привыведет к тому же результату что и наша предыдущая команда.</p>
<h3 id="описание-select">ОПИСАНИЕ SELECT</h3>
<p>В общем случае, команда SELECT начинается с ключевого слова SELECT, сопровождаемого пробелом. После этого должен следовать список имен столбцов которые вы хотите видеть, отделяемые запятыми. Если вы хотите видеть все столбцы таблицы, вы можете заменить этот список звездочкой (*). Ключевое слово FROM следующее далее, сопровождается пробелом и именем таблицы запрос к которой делается. В заключение, точка с запятой (; ) должна использоваться чтобы закончить запрос и указать что команда готова к выполнению.</p>
<h3 id="просмотр-только-определенного-столбца-таблицы">ПРОСМОТР ТОЛЬКО ОПРЕДЕЛЕННОГО СТОЛБЦА ТАБЛИЦЫ</h3>
<p>Команда SELECT способна извлечь строго определенную информацию из таблицы. Сначала, мы можем предоставить возможность увидеть только определенные столбцы таблицы. Это выполняется легко, простым исключением столбцов которые вы не хотите видеть, из части команды SELECT. Например, запрос</p>
<pre><code>SELECT sname, comm
FROM Salespeople;
</code></pre>
<p>будет производить вывод показанный в Таблице 3.2.</p>
<pre><code>SQL Execution Log
SELECT snum, comm FROM Salespeople;
</code></pre>
<table>
<thead>
<tr>
<th>   sname</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   0.12<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   0.13<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   0.11<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   0.15<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   0.10</td>
</tr>
</tbody>
</table>
<p>Таблица 3.2: Выбор определенных столбцов
Могут иметься таблицы которые имеют большое количество столбцов содержащих данные, не все из которых являются относящимися к поставленой задаче. Следовательно, вы можете найти способ подбора и выбора только полезных для Вас столбцов.</p>
<h3 id="переупорядочение-столбца">ПЕРЕУПОРЯДОЧЕНИЕ СТОЛБЦА</h3>
<p>Даже если столбцы таблицы, по определению, упорядоченны, это не означает что вы будете восстанавливать их в том же порядке. Конечно, звездочка (*) покажет все столбцы в их естественном порядке, но если вы укажете столбцы отдельно, вы можете получить их в том порядке котором хотите. Давайте рассмотрим таблицу Порядков, содержащую дату приобретения(odate), номер продавца(snum), номер порядка(onum), и суммы приобретения(amt):</p>
<pre><code>SELECT odate, snum, onum, amt
FROM Orders;
</code></pre>
<p>Вывод этого запроса показан Таблице 3.3.</p>
<pre><code>SQL Execution Log
SELECT odate, snum, onum, amt FROM Orders;
</code></pre>
<table>
<thead>
<tr>
<th>   odate</th>
<th>   snum</th>
<th>   onum</th>
<th>   amt</th>
</tr>
</thead>
<tbody>
<tr>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   18.69<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   3003<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   3002<br style="margin: 0px; padding: 0px;"></td>
<td>   1900.10<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   3005<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   3006<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   3008<br style="margin: 0px; padding: 0px;"></td>
<td>   4723.00<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   3011<br style="margin: 0px; padding: 0px;"></td>
<td>   9891.88<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Рисунок 3.3: Реконструкция столбцов
Как вы можете видеть, структура информации в таблицах - это просто основа для активной перестройки структуры в SQL.
УДАЛЕНИЕ ИЗБЫТОЧНЫХ ДАННЫХ
<strong>DISTINCT</strong> (ОТЛИЧИЕ) - аргумент который обеспечивает Вас способом устранять двойные значения из вашего предложения SELECT. Предположим что вы хотите знать какие продавцы в настоящее время имеют свои порядки в таблице Порядков. Под порядком (здесь и далее) будет пониматься запись в таблицу Порядков, регистрирующую приобретения сделанные в определенный день определенным заказчиком у определенного продавца на определенную сумму). Вам не нужно знать, сколько порядков имеет каждый; вам нужен только список номеров продавцов (snum). Поэтому Вы можете ввести:</p>
<pre><code>SELECT snum
FROM Orders;
</code></pre>
<p>для получения вывода показанного в Таблице 3.4</p>
<pre><code>SQL Execution Log
SELECT snum FROM Orders;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001</td>
</tr>
</tbody>
</table>
<p>Таблица 3.4: SELECT с дублированием номеров продавцов.</p>
<p>Для получения списка без дубликатов, для удобочитаемости, вы можете ввести следующее:
SELECT DISTINCT snum
FROM Orders;</p>
<p>Вывод для этого запроса показан в Таблице 3.5.
Другими словами, DISTINCT следит за тем, какие значения были ранее, так что бы они не были продублированы в списке. Это - полезный способ избежать избыточности данных, но важно что бы при этом вы понимали что вы делаете. Если вы не хотите потерять некоторые данные, вы не должны безоглядно использовать DISTINCT, потому что это может скрыть какую-то проблему или какие-то важные данные. Например, вы могли бы предположить что имена всех ваших заказчиков различны. Если кто-то помещает второго Clemens в таблицу Заказчиков, а вы используете SELECT DISTINCT cname, вы не будете даже знать о существовании двойника. Вы можете получить не того Clemens и даже не знать об этом. Так как вы не ожидаете избыточности, в этом случае вы не должны использовать DISTINCT.</p>
<h3 id="параметры-distinct">ПАРАМЕТРЫ DISTINCT</h3>
<p>DISTINCT может указываться только один раз в данном предложении SELECT. Если предложение выбирает многочисленные поля,</p>
<pre><code>SQL Execution Log
SELECT DISTINCT snum FROM Orders;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 3.5: SELECT без дублирования
DISTINCT опускает строки где все выбранные поля идентичны. Строки в которых некоторые значения одинаковы а некоторые различны - будут сохранены. DISTINCT, фактически, приводит к показу всей строки вывода, не указывая полей (за исключением когда он используется внутри агрегатных функций, как описано в Главе 6 ), так что нет никакого смысла чтобы его повторять.</p>
<h3 id="distinct-вместо-all">DISTINCT ВМЕСТО ALL</h3>
<p>Вместо DISTINCT, вы можете указать - ALL. Это будет иметь противоположный эффект, дублирование строк вывода сохранится. Так как это - тот же самый случай когда вы не указываете ни DISTINCT ни ALL, то ALL - по существу скорее пояснительный, а не действующий аргумент.</p>
<h3 id="квалифицированный-выбор-при-использовании-предложений">КВАЛИФИЦИРОВАННЫЙ ВЫБОР ПРИ ИСПОЛЬЗОВАНИИ ПРЕДЛОЖЕНИЙ</h3>
<p>Таблицы имеют тенденцию становиться очень большими, поскольку с течением времени, все большее и большее количество строк в нее добавляется. Поскольку обычно из них только определенные строки интересуют вас в данное время, SQL дает возможность вам устанавливать критерии чтобы определить какие строки будут выбраны для вывода.
WHERE - предложение команды SELECT, которое позволяет вам устанавливать предикаты, условие которых может быть или верным или неверным для любой строки таблицы. Команда извлекает только те строки из таблицы для которой такое утверждение верно. Например, предположим вы хотите видеть имена и комиссионные всех продавцов в Лондоне. Вы можете ввести такую команду:</p>
<pre><code>SELECT sname, city
FROM Salespeople;
WHERE city=&quot;LONDON&quot;;
</code></pre>
<p>Когда предложение WHERE представлено, программа базы данных просматривает всю таблицу по одной строке и исследует каждую строку чтобы определить верно ли утверждение. Следовательно, для записи Peel, программа рассмотрит текущее значение столбца city, определит что оно равно &quot;London&quot;, и включит эту строку в вывод. Запись для Serres не будет включена, и так далее.
Вывод для вышеупомянутого запроса показан в Таблице 3.6.</p>
<pre><code>SQL Execution Log
SELECT sname, city FROM Salespeople WHERE city='London'
</code></pre>
<table>
<thead>
<tr>
<th>   sname city</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Peel London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Motika London<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Рисунок 3.6: SELECT c предложением WHERE
Давайте попробуем пример с числовым полем в предложении WHERE. Поле rating таблицы Заказчиков предназначено чтобы разделять заказчиков на группы основанные на некоторых критериях которые могут быть получены в итоге через этот номер. Возможно это - форма оценки кредита или оценки основанной на томе предыдущих приобретений. Такие числовые коды могут быть полезны в реляционных базах данных как способ подведения итогов сложной информации. Мы можем выбрать всех заказчиков с рейтингом 100, следующим образом:</p>
<pre><code>SELECT *
FROM Customers
WHERE rating=100;
</code></pre>
<p>Одиночные кавычки не используются здесь потому, что оценка - это числовое поле. Результаты запроса показаны в Таблице 3.7.
Предложение WHERE совместимо с предыдущим материалом в этой главе. Другими словами, вы можете использовать номера столбцов, устранять дубликаты, или переупорядочивать столбцы в команде SELECT которая использует WHERE. Однако, вы можете изменять порядок столбцов для имен только в предложении SELECT, но не в предложении WHERE.</p>
<pre><code>SQL Execution Log
   SELECT * FROM Customers WHERE rating=100;
</code></pre>
<table>
<thead>
<tr>
<th>   сnum</th>
<th>   cname</th>
<th>   city</th>
<th>    rating</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Рисунок 3.7: SELECT с числовым полем в предикате</p>
<h3 id="резюме-2">РЕЗЮМЕ</h3>
<p>Теперь вы знаете несколько способов заставить таблицу давать вам ту информацию какую вы хотите, а не просто выбрасывать наружу все ее содержание. Вы можете переупорядочивать столбцы таблицы или устранять любую из них. Вы можете решать, хотите вы видеть дублированные значения или нет.
Наиболее важно то, что вы можете устанавливать условие называемое предикатом которое определяет или не определяет указанную строку таблицы из тысяч таких же строк, будет ли она выбрана для вывода.
Предикаты могут становиться очень сложными, предоставляя вам высокую точность в решении, какие строки вам выбирать с помощью запроса. Именно эта способность решать точно, что вы хотите видеть, делает запросы SQL такими мощными. Следующие несколько глав будут посвещены, в большей мере, особенностям которые расширяют мощность предикатов. В Главе 4, вам будут представлены операторы иные чем те которые используются в условиях предиката, а также способы объединения многочисленых условий в единый предикат.</p>
<h3 id="работа-с-sql">РАБОТА С SQL</h3>
<ul>
<li>Напишите команду SELECT которая бы вывела номер порядка, сумму, и дату для всех строк из таблицы Порядков.</li>
<li>Напишите запрос который вывел бы все строки из таблицы Заказчиков для которых номер продавца=1001.</li>
<li>Напишите запрос который вывел бы таблицу со столбцами в следующем порядке: city, sname, snum, comm.</li>
<li>Напишите команду SELECT которая вывела бы оценку(rating), сопровождаемую именем каждого заказчика в San Jose.</li>
<li>Напишите запрос который вывел бы значения snum всех продавцов в текущем порядке из таблицы Порядков без каких бы то ни было повторений.</li>
</ul>
<h2 id="глава-4-использование-реляционных-и-булевых-операторов-для-создания-более-изощренных-предикатов">Глава 4. ИСПОЛЬЗОВАНИЕ РЕЛЯЦИОННЫХ И БУЛЕВЫХ ОПЕРАТОРОВ ДЛЯ СОЗДАНИЯ БОЛЕЕ ИЗОЩРЕННЫХ ПРЕДИКАТОВ</h2>
<p>В ГЛАВЕ 3, ВЫ УЗНАЛИ ЧТО ПРЕДИКАТЫ МОГУТ оценивать равенство оператора как верного или неверного. Они могут также оценивать другие виды связей кроме равенств. Эта глава будет исследовать другие реляционные операторы используемые в SQL. Вы также узнаете как использовать операторы Буля, чтобы изменять и объединять значения предиката. С помощью операторов Буля (или проще говоря логических операторов), одиночный предикат может содержать любое число условий. Это позволяет вам создавать очень сложные предикаты. Использование круглых скобок в структуре этих сложных предикатов будет также объясняться.</p>
<h3 id="реляционные-операторы">РЕЛЯЦИОННЫЕ ОПЕРАТОРЫ</h3>
<p>Реляционный оператор - математический символ который указывает на определенный тип сравнения между двумя значениями. Вы уже видели как используются равенства, такие как 2 + 3 = 5 или city = &quot;London&quot;. Но также имеются другие реляционные операторы. Предположим что вы хотите видеть всех Продавцов с их комиссионными выше определенного значения.</p>
<p>Вы можете использовать тип сравнения &quot;больше чем&quot; - (&gt;). Реляционные операторы которыми распологает SQL :</p>
<pre><code>= Равный
&gt; Больше чем
&lt; Меньше чем
&gt;= Больше чем или равно
&lt;= Меньше чем или равно
&lt;&gt; Не равно
</code></pre>
<p>Эти операторы имеют стандартные значения для числовых значений. Для значения символа, их определение зависит от формата преобразования, ASCII или EBCDIC, который вы используете. SQL сравнивает символьные значения в терминах основных номеров как определено в формате преобразования. Даже значение символа, такого как &quot;1&quot;, который представляет номер, не обязательно равняется номеру который он представляет. Вы можете использовать реляционные операторы чтобы установить алфавитный порядок - например, &quot;a&quot; &lt; &quot;n&quot; где средство a первое в алфавитном порядке - но все это ограничивается с помощью параметра преобразования формата.
И в ASCII и в EBCDIC, символы - по значению: меньше чем все другие символы которым они предшествуют в алфавитном порядке и имеют один вариант( верхний или нижний). В ASCII, все символы верхнего регистра меньше чем все символы нижнего регистра, поэтому &quot;Z&quot; &lt; &quot;a&quot;, а все номера - меньше чем все символы, поэтому &quot;1&quot; &lt; &quot;Z&quot;. То же относится и к EBCDIC. Чтобы сохранить обсуждение более простым, мы допустим что вы будете использовать текстовый формат ASCII. Проконсультируйтесь с вашей документацией системы если вы неуверены какой формат вы используете или как он работает.
Значения сравниваемые здесь называются - скалярными значениями. Скалярные значения производяться скалярными выражениями; 1 + 2 - это скалярное выражение которое производит скалярное значение 3. Скалярное значение может быть символом или числом, хотя очевидно что только номера используются с арифметическими операторами, такими как +(плюс) или *(звезда).
Предикаты обычно сравнивают значения скалярных величин, используя или реляционные операторы или специальные операторы SQL чтобы увидеть верно ли это сравнение. Некоторые операторы SQL описаны в Главе 5.
Предположим что вы хотите увидеть всех заказчиков с оценкой(rating) выше 200. Так как 200 - это скалярное значение, как и значение в столбце оценки, для их сравнения вы можете использовать реляционный оператор.</p>
<pre><code>SELECT *
FROM Customers
WHERE rating &gt; 200;
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 4.1.
Конечно, если бы мы захотели увидеть еще и заказчиков с оценкой равной 200, мы стали бы использовать предикат</p>
<pre><code>rating &gt;=200
</code></pre>
<h3 id="булевы-операторы">БУЛЕВЫ ОПЕРАТОРЫ</h3>
<p>Основные Булевы операторы также распознаются в SQL. Выражения Буля - являются или верными или неверными, подобно предикатам. Булевы операторы связывают одно или более верных/неверных значений и производят едиственное верное/или/неверное значение. Стандартными операторами Буля распознаваемыми в SQL являются:</p>
<pre><code>AND, OR, и NOT.
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Customers WHERE rating &gt; 200;
</code></pre>
<p>Таблица 4.1: Использование больше чем (&gt;)
Существуют другие, более сложные, операторы Буля (типа &quot;исключенный или&quot;), но они могут быть сформированы из этих трех простых операторов - AND, OR, NOT.
Как вы можете понять, Булева верня / неверная логика - основана на цифровой компьютерной операции; и фактически, весь SQL( или любой другой язык ) может быть сведен до уровня Булевой логики.
Операторы Буля и как они работают</p>
<ul>
<li>AND берет два Буля (в форме A AND B) как аргументы и оценивает их по отношению к истине, верны ли они оба.</li>
<li>OR берет два Буля (в форме A OR B) как аргументы и оценивает на правильность, верен ли один из них.</li>
<li>NOT берет одиночный Булев (в форме NOT A) как аргументы и заменяет его значение с неверного на верное или верное на неверное.</li>
</ul>
<p>Связывая предикаты с операторами Буля, вы можете значительно увеличить их возможности. Предположим вы хотите видеть всех заказчиков в San Jose которые имеют оценку(рейтинг) выше 200:</p>
<pre><code>SELECT *
FROM Customers
WHERE city=&quot; San Jose'
AND rating &gt; 200;
</code></pre>
<p>Вывод для этого запроса показан на Таблице 4.2. Имеется только один заказчик который удовлетворяет этому условию.
Если вы же используете OR вы получите всех заказчиков которые находились в San Jose или(OR) которые имели оценку выше 200.</p>
<p>SQL Execution Log</p>
<p>SELECT * FROM Customers WHERE city='San Jose' AND rating &gt; 200;</p>
<table>
<thead>
<tr>
<th>   сnum</th>
<th>   cname</th>
<th>   city</th>
<th>   rating</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   Cirneros<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 4.2: SELECT использующий AND</p>
<pre><code>SELECT *
FROM Customers
WHERE city=&quot; San Jose'
OR rating &gt; 200;
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 4.3.
NOT может использоваться для инвертирования значений Буля. Имеется пример запроса с NOT:</p>
<pre><code>SELECT *
FROM Customers
WHERE city=&quot; San Jose'
OR NOT rating &gt; 200;
</code></pre>
<p>Вывод этого запроса показывается в Таблице 4.4.
SQL Execution Log</p>
<pre><code>SELECT * FROM Customers WHERE city='San Jose' OR rating &gt; 200;
</code></pre>
<table>
<thead>
<tr>
<th>   сnum</th>
<th>   cname</th>
<th>   city</th>
<th>   rating</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2003<br style="margin: 0px; padding: 0px;"></td>
<td>   Liu<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   200<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   Grass<br style="margin: 0px; padding: 0px;"></td>
<td>   Berlin<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   Cirneros<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Рисунок 4.4: SELECT использующий NOT
Все записи за исключением Grass были выбраны. Grass не был в San Jose, и его оценка была больше чем 200, так что он потерпел неудачу при обеих проверках. В каждой из других строк встретился один или другой или оба критериев. Обратите внимание что оператор NOT должен предшествовать Булеву оператору, чье значение должно измениться, и не должен помещаться перед реляционным оператором. Например неправильным вводом оценки предиката будет:</p>
<pre><code>rating NOT &gt; 200
</code></pre>
<p>Он выдаст другую отметку. А как SQL оценит следующее?</p>
<pre><code>SELECT *
FROM Customers
WHERE NOT city=&quot; San Jose'
OR rating &gt; 200;
</code></pre>
<p>NOT применяется здесь только к выражению city='SanJose', или к выражению rating &gt; 200 тоже ? Как и написано, правильный ответ будет прежним. SQL может применять NOT с выражением Буля только сразу после него. Вы можете получить другой результат при команде:</p>
<pre><code>SELECT *
FROM Customers
WHERE NOT( city=&quot; San Jose'
OR rating &gt; 200 );
</code></pre>
<p>Здесь SQL понимает круглые скобки как означающие, что все внутри них будет оцениваться первым и обрабатываться как единое выражение с помощью всего что снаружи них (это является стандартной интерпретацией математике). Другими словами, SQL берет каждую строку и определяет, соответствует ли истине равенство city =&quot; San Jose' или равенство rating &gt; 200. Если любое условие верно, выражение Буля внутри круглых скобок верно. Однако, если выражение Буля внутри круглых скобок верно, предикат как единое целое неверен, потому что NOT преобразует верно в неверно и наоборот.
Вывод для этого запроса - показывается в Рисунке 4.5. Имеется намеренно сложный пример. Посмотрим сможете ли вы проследить его логику (вывод показан в Рисунке 4.6 ):</p>
<pre><code>SELECT *
FROM Orders
WHERE NOT ((odate=10/03/1990 AND snum &gt;1002)
OR amt &gt; 2000.00);
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Customers WHERE NOT
(city='San Jose' OR rating &gt; 200);
</code></pre>
<table>
<thead>
<tr>
<th>   сnum</th>
<th>   cname</th>
<th>   city</th>
<th>   rating</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   Giovanni<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   200<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Рисунок 4.5: SELECT использующий NOT и вводное предложение</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Orders WHERE NOT
((odate=10/03/1990 AND snum &gt; 1002)OR amt &gt; 2000.00);
</code></pre>
<table>
<thead>
<tr>
<th>   onum</th>
<th>   amt</th>
<th>   odate</th>
<th>   cnum</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   3003<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Рисунок 4.6: Полный (комплексный) запрос
Несмотря на то что Булевы опреаторы индивидуально просты, они не так просты когда комбинируются в комплексное выражение.
Способ оценки комплекса Булева состоит в том, чтобы оценивать Булевы выражения наиболее глубоко вложенные в круглых скобках, объединять их в единичное Булево значение, и затем объединять его с верхними значениями.
Имеется подробное объяснение того как пример выше был вычислен. Наиболее глубоко вложенные выражения Буля в предикате - это odate=10/03/1990 и snum &gt; 1002 являются объединеными с помощью AND, формируя одно выражение Буля которое будет оценено как верное для всех строк в которых встретились оба эти условия. Это составное Булево выражение (которое мы будем называть Булево номер 1, или B1 для краткости) объдиняется с выражением (amt) &gt; 2000.00 (B2) с помощью OR, формируя третье выражение (B3), которое является верным для данной строки, если или B1 или B2 - верны для этой строки.
B3 полностью содержится в круглых скобках которым предшествует NOT, формируя последнее выражение Буля(B4), которое является условием предиката.
Таким образом B4, предикат запроса, - будет верен всякий раз, когда B3 неправилен. B3 - неправилен всегда, когда B1 и B2 - оба неверны. B1 неправилен для строки если дата порядка строки не 10/03/1990, или если значение snum не большее чем 1002. B2 неправилен для всех строк, значения суммы приобретений которых не превышает 2000.00. Любая строка со значением выше 2000.00 сделает B2 - верным; в результате B3 будет верен, а B4 нет. Следовательно, все эти строки будут удалены из вывода.
Из оставшихся, строки которые на 3 Октября имеют snum &gt; 1002 (такие как строки для onum 3001 на 3 Октября со snum=1007 ), делают B1 верным, с помощью верного B3 и неверного предиката запроса. Они будут также удалены из вывода. Вывод показан для строк которые оставлены.</p>
<h3 id="резюме-3">РЕЗЮМЕ</h3>
<p>В этой главе, вы значительно расширили ваше знакомство с предикатами. Теперь вы можете находить значения которые связаны с данным значением любым способом - определяемым различными реляционными операторами.</p>
<p>Вы можете также использовать операторы Буля AND и OR чтобы много условий, каждое из которых автономно в предикатах, объединять в единый предикат. Оператор Буля NOT, как вы уже видели, может изменять значение условия или группы условий на противоположное.
Булевы и Реляционные операторы могут эффективно управляться с помощью круглых скобок, которые определяют порядок, в котором операции будут выполнены. Эти операции применимы к любому уровню сложности и вы поняли как сложные условия могут создаваться из этих простых частей.
Теперь, когда мы показали как используются стандартные математические операторы, мы можем перейти к операторам которые являются исключительными в SQL. Это мы сделаем в Главе 5.</p>
<h3 id="работа-с-sql-1">РАБОТА С SQL</h3>
<ul>
<li>Напишите запрос который может дать вам все порядки со значениями суммы выше чем $1,000.</li>
<li>Напишите запрос который может выдать вам поля sname и city для всех продавцов в Лондоне с комиссионными выше .10 .</li>
<li>Напишите запрос к таблице Заказчиков чей вывод может включить всех заказчиков с оценкой=&lt; 100, если они не находятся в Риме.</li>
<li>Что может быть выведено в результате следующего запроса?</li>
</ul>
<pre><code>SELECT *
FROM Orders
WHERE (amt &lt; 1000 OR
NOT (odate=10/03/1990
AND cnum &gt; 2003 ));
</code></pre>
<ul>
<li>Что может быть выведено в результате следующего запроса?</li>
</ul>
<pre><code>SELECT *
FROM Orders
WHERE NOT ((odate=10/03/1990 OR snum &gt; 1006)
AND amt &gt;=1500 );
</code></pre>
<ul>
<li>Как можно проще переписать такой запрос?</li>
</ul>
<pre><code>SELECT snum, sname, city, comm
FROM Salespeople
WHERE (comm &gt; + .12 OR
comm &lt; .14 );
</code></pre>
<h2 id="глава-5-использование-специальных-операторов-в-условиях">Глава 5. ИСПОЛЬЗОВАНИЕ СПЕЦИАЛЬНЫХ ОПЕРАТОРОВ В УСЛОВИЯХ</h2>
<p>В ДОПОЛНЕНИИ К РЕЛЯЦИОННЫМ И БУЛЕВСКИМ операторам обсуждаемым в Главе 4, SQL использует специальные операторы IN, BETWEEN, LIKE, и IS NULL. В этой главе, вы узнаете как их использовать и как реляционные операторы позволяют создавать более сложные и мощные предикаты. Обсуждение оператора IS NULL будет включать отсутствие данных и значение NULL, которое указывает на то: что данные отсутствуют. Вы также узнаете о разновидностях использования оператора NOT применяющегося с этими операторами.</p>
<h3 id="оператор-in">ОПЕРАТОР IN</h3>
<p>Оператор IN определяет набор значений в которое данное значение может или не может быть включено. В соответствии с нашей учебной базой данных на которой вы обучаетесь по настоящее временя, если вы хотите найти всех продавцов, которые размещены в Barcelona или в London, вы должны использовать следующий запрос (вывод показывается в Таблице5.1 ):</p>
<pre><code>SELECT *
FROM Salespeople
WHERE city='Barcelona'
OR city='London';
</code></pre>
<p>Имеется и более простой способ получить ту же информацию:</p>
<pre><code>SELECT *
FROM Salespeople
WHERE city IN ('Barcelona', 'London' );
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 5.2.
Как вы можете видеть, IN определяет набор значений с помощью имен членов набора заключеных в круглые скобки и отделенных запятыми. Он затем проверяет различные значения указанного поля пытаясь найти совпадение со значениями из набора. Если это случается, то предикат верен. Когда наборсодержит значения номеров а не символов, одиночные кавычки опускаются. Давайте найдем всех заказчиков относящихся к продавцам имеющих значения snum=1001, 1007, и 1004. Вывод для следующего запроса показан в Таблице 5.3:</p>
<pre><code>SELECT *
FROM Customers
WHERE cnum IN (1001, 1007, 1004 );
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Salespeople WHERE city=
'Barcelona' OR city='London';
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.12<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.11<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   0.15<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5.1 Нахождение продавцов в Барселоне и Лондоне</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Salespeople WHERE city IN
('Barcelona', 'London');
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.12<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.11<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   0.15<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5.2 SELECT использует IN</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Customers WHERE snum IN (1001, 1007, 1004 );
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   cname</th>
<th>   city</th>
<th>   rating</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5.3: SELECT использует IN с номерами</p>
<h3 id="оператор-between">ОПЕРАТОР BETWEEN</h3>
<p>Оператор BETWEEN похож на оператор IN. В отличии от определения по номерам из набора, как это делает IN, BETWEEN определяет диапазон, значения которого должны уменьшаться что делает предикат верным. Вы должны ввести ключевое слово BETWEEN с начальным значением, ключевое AND и конечное значение. В отличие от IN, BETWEEN чувствителен к порядку, и первое значение в предложении должно быть первым по алфавитному или числовому порядку. (Обратите Внимание что, в отличие от Английского языка, SQL не говорит что &quot;значение находится (между)BETWEEN значением и значением|, а просто &quot;значение BETWEEN значение значение|.
Это применимо и к оператору LIKE). Следующий пример будет извлекать из таблицы Продавцов всех продавцов с комиссионными между .10 и .12 (вывод показывается в Таблице 5.4):</p>
<pre><code>SELECT *
FROM Salespeople
WHERE comm BETWEEN .10 AND .12;
</code></pre>
<p>Для включенного оператора BETWEEN, значение совпадающее с любым из двух значений границы (в этом случае, .10 и .12 ) заставляет предикат быть верным.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Salespeople WHERE comm BETWEEN .10 AND .12;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.12<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.11<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   0.10<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5.4: SELECT использует BETWEEN
SQL не делает непосредственной поддержки невключения BETWEEN. Вы должны или определить ваши граничные значения так, чтобы включающая интерпретация была приемлема, или сделать что-нибудь типа этого:</p>
<pre><code>SELECT *
FROM Salespeople
WHERE (comm BETWEEN .10, AND .12 )
AND NOT comm IN (.10, .12 );
</code></pre>
<p>Вывод для этого запроса показывается в Таблица 5.5. По общему признанию, это немного неуклюже, но зато показывает как эти новые операторы могут комбинироваться с операторами Буля чтобы производить более сложные предикаты. В основном, вы используете IN и BETWEEN также как вы использовали реляционные операторы чтобы сравнивать значения, которые берутся либо из набора (для IN ) либо из диапазона (для BETWEEN ).
Также, подобно реляционным операторам, BETWEEN может работать с символьными полями в терминах эквивалентов ASCII. Это означает что вы можете использовать BETWEEN чтобы выбирать ряд значений из упорядоченных по алфавиту значений.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Salespeople WHERE
( comm BETWEEN .10 AND .12 AND NOT comm IN (.10 .12);
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.11<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5.5: Сделать BETWEEN - невключенным
Этот запрос выбирает всех заказчиков чьи имена попали в определенный алфавитный диапазон:</p>
<pre><code>SELECT *
FROM Customers
WHERE cname BETWEEN 'A' AND 'G';
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 5.6.
Обратите Внимание что Grass и Giovanni отсутствуют, даже при включенном BETWEEN. Это происходит из-за того что BETWEEN сравнивает строк неравной длины. Строка 'G' более короткая чем строка Giovanni, поэтому BETWEEN выводит 'G' с пробелами. Пробелы предшествуют символам в алфавитном порядке (в большинстве реализаций ), поэтому Giovanni не выбирается. То же самое происходит с Grass. Важно помнить это когда вы используете BETWEEN для извлечения значений из алфавитных диапазонов.
Обычно вы указываете диапазон с помощью символа начала диапазона и символа конца( вместо которого можно просто поставить z ).</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Customers WHERE cname BETWEEN 'A' AND 'G';
</code></pre>
<table>
<thead>
<tr>
<th>   cnum</th>
<th>   cname</th>
<th>   city</th>
<th>   rating</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   100<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5. 6: Использование BETWEEN в алфавитных порядках
ОПЕРАТОР LIKE
LIKE применим только к полям типа CHAR или VARCHAR, с которыми он используется чтобы находить подстроки. Т.е. он ищет поле символа чтобы видеть, совпадает ли с условием часть его строки. В качестве условия он использует групповые символы(wildkards) - специальные символы которые могут соответствовать чему-нибудь.</p>
<ul>
<li>Имеются два типа групповых символов используемых с LIKE:
символ подчеркивания (_ ) замещает любой одиночный символ. Например, 'b_t' будет соответствовать словам 'bat' или 'bit', но не будет</li>
<li>соответствовать 'brat'.
знак процента (%) замещает последовательность любого числа символов
(включая символы нуля). Например '%p%t' будет соответствовать словам
'put', 'posit', или 'opt', но не 'spite'.</li>
</ul>
<p>Давайте найдем всех заказчиков чьи имена начинаются с G (вывод показывается в Таблице 5.7 ):</p>
<pre><code>SELECT
FROM Customers
WHERE cname LIKE 'G%';
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Customers WHERE cname LIKE 'G';
</code></pre>
<table>
<thead>
<tr>
<th>   cnum</th>
<th>   cname</th>
<th>   city</th>
<th>   rating</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   Giovanni<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   200<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   Grass<br style="margin: 0px; padding: 0px;"></td>
<td>   Berlin<br style="margin: 0px; padding: 0px;"></td>
<td>   300<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5. 7: SELECT использует LIKE с %</p>
<p>LIKE может быть удобен если вы ищете имя или другое значение, и если вы не помните как они точно пишутся. Предположим что вы неуверены как записано по буквам имя одного из ваших продавцов Peal или Peel. Вы можете просто использовать ту часть которую вы знаете и групповые символы чтобы находить все возможные пары (вывод этого запроса показывается в Таблице 5.8 ):</p>
<pre><code>SELECT *
FROM Salespeople
WHERE sname LIKE 'P _ _ l %';
</code></pre>
<p>Групповые символы подчеркивания, каждый из которых представляет один символ, добавят только два символа к уже существующим 'P' и 'l', поэтому имя наподобии Prettel не может быть показано. Групповой символ ' % ' - в конце строки необходим в большинстве реализаций если длина поля sname больше чем число символов в имени Peel (потому что некоторые другие значения sname - длиннее чем четыре символа). В таком случае, значение поля sname, фактически сохраняемое как имя Peel, сопровождается рядом пробелов. Следовательно, символ 'l' не будет рассматриваться концом строки. Групповой символ ' % ' - просто соответствует этим пробелам. Это необязательно, если поля sname имеет тип - VARCHAR.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Salespeople WHERE sname LIKE ' P 1% ';
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.12<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5.8: SELECT использует LIKE с подчеркиванием (_)
А что же Вы будете делать если вам нужно искать знак процента или знак подчеркивания в строке? В LIKE предикате, вы можете определить любой одиночный символ как символ ESC. Символ ESC используется сразу перед процентом или подчеркиванием в предикате, и означает что процент или подчеркивание будет интерпретироваться как символ а не как групповой символ. Например, мы могли бы найти наш sname столбец где присутствует подчеркивание, следующим образом:</p>
<pre><code>SELECT *
FROM Salespeople
WHERE sname LIKE '%/_%'ESCAPE'/';
</code></pre>
<p>С этими данными не будет никакого вывода, потому что мы не включили никакого подчеркивания в имя нашего продавца. Предложение ESCAPE определяет '/ ' как символ ESC. Символ ESC используемый в LIKE строке, сопровождается знаком процента, знаком подчеркивания, или знаком ESCAPE, который будет искаться в столбце, а не обрабатываться как групповой символ. Символ ESC должен быть одиночным символом и применяться только к одиночному символу сразу после него.
В примере выше, символ процента начала и символ процента окончания обрабатываются как групповые символы; только подчеркивание предоставлено само себе.
Как упомянуто выше, символ ESC может также использоваться самостоятельно. Другими словами, если вы будете искать столбец с вашим символом ESC, вы просто вводите его дважды. Во-первых это будет означать что символ ESC &quot;берет следующий символ буквально как символ&quot;, и во-вторых что символ ESC самостоятелен.
Имеется предыдущий пример который пересмотрен чтобы искать местонахождение строки '_/' в sname столбце:</p>
<pre><code>SELECT *
FROM Salespeople
WHERE sname LIKE ' % /_ / / %'ESCAPE'/';
</code></pre>
<p>Снова не будет никакого вывода с такими данными. Строка сравнивается с содержанием любой последовательности символов (%), сопровождаемых символом подчеркивания (/_ ), символом ESC (// ), и любой последовательностью символов в конце строки (% ).</p>
<h3 id="работа-с-нулевыми-null--значениями">РАБОТА С НУЛЕВЫМИ( NULL ) ЗНАЧЕНИЯМИ</h3>
<p>Часто, будут иметься записи в таблице которые не имеют никаких значений для каждого поля, например потому что информация не завершена, или потому что это поле просто не заполнялось. SQL учитывает такой вариант, позволяя вам вводить значение NULL(ПУСТОЙ) в поле, вместо значения. Когда значение поля равно NULL, это означает, что программа базы данных специально промаркировала это поле как не имеющее никакого значения для этой строки (или записи). Это отличается от просто назначения полю, значения нуля или пробела, которые база данных будет обрабатывать также как и любое другое значение. Точно также, как NULL не является техническим значением, оно не имеет и типа данных. Оно может помещаться в любой тип поля. Тем ни менее, NULL в SQL часто упоминается как нуль.
Предположим, что вы получили нового заказчика который еще не был назначен продавцу. Чем ждать продавца к которому его нужно назначить, вы можете ввести заказчика в базу данных теперь же, так что он не потеряется при перестановке.
Вы можете ввести строку для заказчика со значением NULL в поле snum и заполнить это поле значением позже, когда продавец будет назначен.</p>
<h3 id="null-оператор">NULL ОПЕРАТОР</h3>
<p>Так как NULL указывает на отсутствие значения, вы не можете знать каков будет результат любого сравнения с использованием NULL. Когда NULL сравнивается с любым значением, даже с другим таким же NULL, результат будет ни верным ни неверным, он - неизвестен. Неизвестный Булев, вообще ведет себя также как неверная строка, которая произведя неизвестное значение в предикате не будет выбрана запросом - имейте ввиду что в то время как NOT(неверное) - равнятся верно, NOT (неизвестное) - равняется неизвестно.
Следовательно, выражение типа 'city=NULL' или 'city IN (NULL)' будет неизвестно, независимо от значения city.
Часто вы должны делать различия между неверно и неизвестно - между строками содержащими значения столбцов которые не соответствуют условию предиката и которые содержат NULL в столбцах. По этой причине, SQL предоставляет специальный оператор IS, который используется с ключевым словом NULL, для размещения значения NULL.
Найдем все записи в нашей таблице Заказчиков с NULL значениями в city столбце:</p>
<pre><code>SELECT *
FROM Customers
WHERE city IS NULL;
</code></pre>
<p>Здесь не будет никакого вывода, потому что мы не имеем никаких значений NULL в наших типовых таблицах. Значения NULL - очень важны, и мы вернемся к ним позже.</p>
<h3 id="использование-not-со-специальными-операторами">ИСПОЛЬЗОВАНИЕ NOT СО СПЕЦИАЛЬНЫМИ ОПЕРАТОРАМИ</h3>
<p>Специальные операторы которые мы изучали в этой главе могут немедленно предшествовать Булеву NOT.
Он противоположен реляционным операторам, которые должны иметь оператор NOT - вводимым выражением. Например, если мы хотим устранить NULL из нашего вывода, мы будем использовать NOT чтобы изменить на противоположное значение предиката:</p>
<pre><code>SELECT *
FROM Customers
WHERE city NOT NULL;
</code></pre>
<p>При отсутствии значений NULL( как в нашем случае ), будет выведена вся таблица Заказчиков. Аналогично можно ввести следующее</p>
<pre><code>SELECT *
FROM Customers
WHERE NOT city IS NULL;
</code></pre>
<ul>
<li>что также приемлемо.
Мы можем также использовать NOT с IN:</li>
</ul>
<pre><code>SELECT *
FROM Salespeople
WHERE city NOT IN ('London', 'San Jose' );
</code></pre>
<p>А это - другой способ подобного же выражения</p>
<pre><code>SELECT *
FROM Salespeople
WHERE NOT city IN ('London', ' San Jose' );
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 5.9.
Таким же способом Вы можете использовать NOT BETWEEN и NOT LIKE.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Salespeople WHERE sity NOT IN
('London', 'San Jose');
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   0.15<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   0.10<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 5. 9: Использование NOT с IN</p>
<h3 id="резюме-4">РЕЗЮМЕ</h3>
<p>Теперь вы можете создавать предикаты в терминах связей специально определенных SQL. Вы можете искать значения в определенном диапазоне (BETWEEN) или в числовом наборе (IN), или вы можете искать символьные значения которые соответствуют тексту внутри параметров (LIKE).
Вы также изучили некоторые вещи относительно того как SQL поступает при отсутствии данных - что реальность мировой базы данных - используя NULL вместо конкретных значений. Вы можете извлекать или исключать значения NULL из вашего вывода используя оператор IS NULL. Теперь, когда вы имеете в вашем распоряжении весь набор стандартных математических и специальных операторов, вы можете переходить к специальным функциям SQL которые работают на всех группах значений, а не просто на одиночном значении, что важно.
Это уже тема Главы 6.</p>
<h3 id="работа-с-sql-2">РАБОТА С SQL</h3>
<p>Напишите два запроса которые могли бы вывести все порядки на 3 или 4 Октября 1990</p>
<ul>
<li>Напишите запрос который выберет всех заказчиков обслуживаемых продавцами Peel или Motika. (Подсказка: из наших типовых таблиц, поле snum связывает вторую таблицу с первой )</li>
<li>Напишите запрос, который может вывести всех заказчиков чьи имена начинаются с буквы попадающей в диапазон от A до G.</li>
<li>Напишите запрос который выберет всех пользователей чьи имена начинаются с буквы C.</li>
<li>Напишите запрос который выберет все порядки имеющие нулевые значения или NULL в поле amt(сумма).</li>
</ul>
<h2 id="глава-6-обобщение-данных-с-помощью-агрегатных-функций">Глава 6. ОБОБЩЕНИЕ ДАННЫХ С ПОМОЩЬЮ АГРЕГАТНЫХ ФУНКЦИЙ</h2>
<p>В ЭТОЙ ГЛАВЕ, ВЫ ПЕРЕЙДЕТЕ ОТ ПРОСТОГО использования запросов к извлечению значений из базы данных и определению, как вы можете использовать эти значения чтобы получить из них информацию. Это делается с помощью агрегатных или общих функций которые берут группы значений из поля и сводят их до одиночного значения. Вы узнаете как использовать эти функции, как определить группы значений к которым они будут применяться, и как определить какие группы выбираются для вывода. Вы будете также видеть при каких условиях вы сможете объединить значения поля с этой полученной информацией в одиночном запросе.</p>
<h3 id="что-такое-агрегатные-функции">ЧТО ТАКОЕ АГРЕГАТНЫЕ ФУНКЦИИ?</h3>
<p>Запросы могут производить обобщенное групповое значение полей точно также как и значение одного поля. Это делает с помощью агрегатых функций. Агрегатные функции производят одиночное значение для всей группы таблицы. Имеется список этих функций:</p>
<ul>
<li>COUNT производит номера строк или не-NULL значения полей которые выбрал запрос.</li>
<li>SUM производит арифметическую сумму всех выбранных значений данного поля.</li>
<li>AVG производит усреднение всех выбранных значений данного поля.</li>
<li>MAX производит наибольшее из всех выбранных значений данного поля.</li>
<li>MIN производит наименьшее из всех выбранных значений данного поля.</li>
</ul>
<h3 id="как-использовать-агрегатные-функции">КАК ИСПОЛЬЗОВАТЬ АГРЕГАТНЫЕ ФУНКЦИИ?</h3>
<p>Агрегатные функции используются подобно именам полей в предложении SELECT запроса, но с одним исключением, они берут имена поля как аргументы. Только числовые поля могут использоваться с SUM и AVG. С COUNT, MAX, и MIN, могут использоваться и числовые или символьные поля. Когда они используются с символьными полями, MAX и MIN будут транслировать их в эквивалент ASCII, который должен сообщать, что MIN будет означать первое, а MAX последнее значение в алфавитном порядке( выдача алфавит ного упорядочения обсуждается более подробно в Главе 4). Чтобы найти SUM всех наших покупок в таблицы Порядков, мы можем ввести следующий запрос, с его выводом в Таблице 6.1:</p>
<pre><code>SELECT SUM ((amt))
FROM Orders;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT SUM (amt) FROM Orders;
</code></pre>
<table>
<thead>
<tr>
<th>   26658.4</th>
</tr>
</thead>
</table>
<p>Таблица 6.1: Выбор суммы
Это конечно, отличается от выбора поля при котором возвращается одиночное значение, независимо от того сколько строк находится в таблице.
Из-за этого, агрегатные функции и поля не могут выбираться одновременно, пока предложение GROUP BY (описанное далее) не будет использовано.
Нахождение усредненой суммы - это похожая операция (вывод следующего запроса показывается в Таблице 6.2 ):</p>
<pre><code>SELECT AVG (amt)
FROM Orders;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT AVG (amt) FROM Orders;
</code></pre>
<table>
<thead>
<tr>
<th>   5</th>
</tr>
</thead>
</table>
<p>Таблица 6.3: Подсчет значений поля
Вы можете выбирать многочисленые счета( COUNT ) из полей с помощью DISTINCT в одиночном запросе который, как мы видели в Главе 3, не выполнялся когда вы выбирали строки с помощью DISTINCT. DISTINCT может использоваться таким образом, с любой функцией агрегата, но наиболее часто он используется с COUNT. С MAX и MIN, это просто не будет иметь никакого эффекта, а SUM и AVG, вы обычно применяете для включения повторяемых значений, так как они законно эффективнее общих и средних значений всех столбцов.</p>
<h3 id="использование-count-со-строками-а-не-значениями">ИСПОЛЬЗОВАНИЕ COUNT СО СТРОКАМИ, А НЕ ЗНАЧЕНИЯМИ</h3>
<p>Чтобы подсчитать общее число строк в таблице, используйте функцию COUNT со звездочкой вместо имени поля, как например в следующем примере, вывод из которого показан в Таблице.4:</p>
<pre><code>SELECT COUNT (*)
FROM Customers
</code></pre>
<p>COUNT со звездочкой включает и NULL и дубликаты, по этой причине DISTINCT не может быть использован. DISTINCT может производить более высокие номера чем COUNT особого поля, который удаляет все строки, имеющие избыточные или NULL данные в этом поле.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT COUNT (*) FROM Customers;
</code></pre>
<table>
<thead>
<tr>
<th>   7</th>
</tr>
</thead>
</table>
<p>Таблица 6. 4: Подсчет строк вместо значений</p>
<p>DISTINCT не применим c COUNT (*), потому, что он не имеет никакого действия в хорошо разработаной и поддерживаемой базе данных. В такой базе данных, не должно быть ни таких строк, которые бы являлись полностью пустыми, ни дубликатов (первые не содержат никаких данных, а последние полностью избыточны). Если, с другой стороны, все таки имеются полностью пустые или избыточные строки, вы вероятно не захотите чтобы COUNT скрыл от вас эту информацию.</p>
<h3 id="включение-дубликатов-в-агрегатные-функции">ВКЛЮЧЕНИЕ ДУБЛИКАТОВ В АГРЕГАТНЫЕ ФУНКЦИИ</h3>
<p>Агрегатные функции могут также (в большинстве реализаций ) использовать аргумент ALL, который помещается перед именем поля, подобно DISTINCT, но означает противоположное: - включать дубликаты. ANSI технически не позволяет этого для COUNT, но многие реализации ослабляют это ограничение.
Различия между ALL и * когда они используются с COUNT -</p>
<ul>
<li>ALL использует имя_поля как аргумент.</li>
<li>ALL не может подсчитать значения NULL.</li>
</ul>
<p>Пока * является единственым аргументом который включает NULL значения, и он используется только с COUNT; функции отличные от COUNT игнорируют значения NULL в любом случае. Следующая команда подсчитает(COUNT) число не-NULL значений в поле rating в таблице Заказчиков (включая повторения ):</p>
<pre><code>SELECT COUNT (ALL rating )
FROM Customers;
</code></pre>
<h3 id="агрегаты-построенные-на-скалярном-выражении">АГРЕГАТЫ ПОСТРОЕННЫЕ НА СКАЛЯРНОМ ВЫРАЖЕНИИ</h3>
<p>До этого, вы использовали агрегатные функции с одиночными полями как аргументами. Вы можете также использовать агрегатные функции с аргументами которые состоят из скалярных выражений включающих одно или более полей. (Если вы это делаете, DISTINCT не разрешается. ) Предположим, что таблица Порядков имеет еще один столбец который хранит предыдущий неуплаченый баланс (поле blnc) для каждого заказчика. Вы должны найти этот текущий баланс, добавлением суммы приобретений к предыдущему балансу. Вы можете найти наибольший неуплаченый баланс следующим образом:</p>
<pre><code>SELECT MAX (blnc + (amt) )
FROM Orders;
</code></pre>
<p>Для каждой строки таблицы, этот запрос будет складывать blnc и amt для этого заказчика и выбирать самое большое значение которое он найдет. Конечно, пока заказчики могут иметь многочисленые порядки, их неуплаченый баланс оценивается отдельно для каждого порядка. Возможно, порядок с более поздней датой будет иметь самый большой неуплаченый баланс. Иначе, старый баланс должен быть выбран как в запросе выше. Фактически, имеются большое количество ситуаций в SQL где вы можете использовать скалярные выражения с полями или вместо полей, как вы увидете это в Главе 7.</p>
<h3 id="предложение-group-by">ПРЕДЛОЖЕНИЕ GROUP BY</h3>
<p>Предложение GROUP BY позволяет вам определять подмножество значений в особом поле в терминах другого поля, и применять функцию агрегата к подмножеству. Это дает вам возможность объединять поля и агрегатные функции в едином предложении SELECT. Например, предположим что вы хотите найти наибольшую сумму приобретений полученную каждым продавцом.
Вы можете сделать раздельный запрос для каждого из них, выбрав MAX (amt) из таблицы Порядков для каждого значения поля snum. GROUP BY, однако, позволит Вам поместить их все в одну команду:</p>
<pre><code>SELECT snum, MAX (amt)
FROM Orders
GROUP BY snum;
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 6.5.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, MAX (amt) FROM Orders GROUP BY snum;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1014<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 6.5: Нахождение максимальной суммы продажи у каждого продавца</p>
<p>GROUP BY применяет агрегатные функции независимо от серий групп которые определяются с помощью значения поля в целом. В этом случае, каждая группа состоит из всех строк с тем же самым значением поля snum, и MAX функция применяется отдельно для каждой такой группы. Это значение поля, к которому применяется GROUP BY, имеет, по определению, только одно значение на группу вывода, также как это делает агрегатная функция. Результатом является совместимость которая позволяет агрегатам и полям объединяться таким образом.
Вы можете также использовать GROUP BY с многочислеными полями. Совершенствуя вышеупомянутый пример далее, предположим что вы хотите увидеть наибольшую сумму приобретений получаемую каждым продавцом каждый день. Чтобы сделать это, вы должны сгруппировать таблицу Порядков по датам продавцов, и применить функцию MAX к каждой такой группе, подобно этому:</p>
<pre><code>SELECT snum, odate, MAX ((amt))
FROM Orders
GROUP BY snum, odate;
</code></pre>
<p>Вывод для этого запроса показывается в Рисунке 6.6.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, odate, MAX (amt)
FROM Orders GROUP BY snum, odate;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   odate</th>
<th>  </th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   4723.00<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   9891.88<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1014<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1900.10<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 6.6: Нахождение наибольшей суммы приобретений на каждый день
Конечно же, пустые группы, в дни когда текущий продавец не имел порядков, не будут показаны в выводе.</p>
<h3 id="предложение-having">ПРЕДЛОЖЕНИЕ HAVING</h3>
<p>Предположим, что в предыдущем примере, вы хотели бы увидеть только максимальную сумму приобретений значение которой выше $3000.00. Вы не сможете использовать агрегатную функцию в предложении WHERE (если вы не используете подзапрос, описанный позже ), потому что предикаты оце ниваются в терминах одиночной строки, а агрегатные функции оцениваются в терминах групп строк. Это означает что вы не сможете сделать что-нибудь подобно следующему:</p>
<pre><code>SELECT snum, odate, MAX (amt)
FROM Oreders
WHERE MAX ((amt)) &gt; 3000.00
GROUP BY snum, odate;
</code></pre>
<p>Это будет отклонением от строгой интерпретации ANSI. Чтобы увидеть максимальную стоимость приобретений свыше $3000.00, вы можете использовать предложение HAVING.
Предложение HAVING определяет критерии используемые чтобы удалять определенные группы из вывода, точно также как предложение WHERE делает это для индивидуальных строк.
Правильной командой будет следующяя:</p>
<pre><code>SELECT snum, odate, MAX ((amt))
FROM Orders
GROUP BY snum, odate
HAVING MAX ((amt)) &gt; 3000.00;
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 6. 7.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, odate, MAX (amt) FROM Orders
GROUP BY snum, odate HAVING MAX (amt) &gt; 3000.00;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   odate</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 6. 7: Удаление групп агрегатных значений
Аргументы в предложении HAVING следуют тем же самым правилам что и в предложении SELECT, состоящей из команд использующих GROUP BY. Они должны иметь одно значение на группу вывода. Следующая команда будет запрещена:</p>
<pre><code>SELECT snum, MAX (amt)
FROM Orders
GROUP BY snum
HAVING odate=10/03/1988;
</code></pre>
<p>Поле оdate не может быть вызвано предложением HAVING, потому что оно может иметь (и действительно имеет ) больше чем одно значение на группу вывода. Чтобы избегать такой ситуации, предложение HAVING должно ссылаться только на агрегаты и поля выбранные GROUP BY. Имеется правильный способ сделать вышеупомянутый запрос( вывод показывается в Таблице 6.8 ):</p>
<pre><code>SELECT snum, MAX (amt)
FROM Orders
WHEREodate=10/03/1990
GROUP BY snum;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, odate, MAX (amt)
FROM Orders GROUP BY snum, odate;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1014<br style="margin: 0px; padding: 0px;"></td>
<td>   1900.10<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 6.8: Максимальное значение суммы приобретений у каждого
продавца на 3 Октября
Поскольку поля odate нет, не может быть и выбраных полей, значение этих данных меньше чем в некоторых других примерах. Вывод должен вероятно включать что-нибудь такое что говорит - &quot; это - самые большие порядки на 3 Октября.&quot; В Главе 7, мы покажем как вставлять текст в ваш вывод.
Как и говорилось ранее, HAVING может использовать только аргументы которые имеют одно значение на группу вывода. Практически, ссылки на агрегатные функции - наиболее общие, но и поля выбранные с помощью GROUP BY также допустимы. Например, мы хотим увидеть наибольшие порядки для Serres и Rifkin:</p>
<pre><code>SELECT snum, MAX (amt)
FROM Orders
GROUP BY snum
HAVING snum B (1002,1007);
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 6.9.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, MAX (amt)| FROM Orders
GROUP BY snum HAVING snum IN (1002, 1007 );
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 6. 9: Использование HAVING с GROUP BY полями</p>
<h3 id="не-делайте-вложенных-агрегатов">НЕ ДЕЛАЙТЕ ВЛОЖЕННЫХ АГРЕГАТОВ</h3>
<p>В строгой интерпретации ANSI SQL, вы не можете использовать агрегат агрегата. Предположим что вы хотите выяснять, в какой день имелась наибольшая сумма приобретений. Если вы попробуете сделать это, то ваша</p>
<p>SELECT odate, MAX (SUM (amt) )
FROM Orders
GROUP BY odate;</p>
<p>команда будет вероятно отклонена. (Некоторые реализации не предписывают этого ограничения, которое является выгодным, потому что вложенные агрегаты могут быть очень полезны, даже если они и несколько проблематичны.) В вышеупомянутой команде, например, SUM должен применяться к каждой группе поля odate, а MAX ко всем группам, производящим одиночное значение для всех групп. Однако предложение GROUP BY подразумевает что должна иметься одна строка вывода для каждой группы поля odate.</p>
<h3 id="резюме-5">РЕЗЮМЕ</h3>
<p>Теперь вы используете запросы несколько по-другому. Способность получать, а не просто размещать значения, очень мощна. Это означает что вы не обязательно должны следить за определенной информацией если вы можете сформулировать запрос так чтобы ее получить. Запрос будет давать вам по-минутные результаты, в то время как таблица общего или среднего значений будет хороша только некоторое время после ее модификации. Это не должно наводить на мысль, что агрегатные функции могут полностью вытеснить потребность в отслеживании информации такой например как эта.
Вы можете применять эти агрегаты для групп значений определенны предложением GROUP BY. Эти группы имеют значение поля в целом, и могут постоянно находиться внутри других групп которые имеют значение поля в целом. В то же время, предикаты еще используются чтобы определять какие строки агрегатной функции применяются.
Объединенные вместе, эти особенности делают возможным, производить агрегаты основанные на сильно определенных подмножествах значений в поле. Затем вы можете определять другое условие для исключения определенных результатов групп с предложением HAVING.
Теперь, когда вы стали знатоком большого количества того как запрос производит значения, мы покажем вам, в Главе 7, некоторые вещи которые вы можете делать со значениями которые он производит.</p>
<p>РАБОТА С SQL</p>
<ul>
<li>Напишите запрос который сосчитал бы все суммы приобретений на 3 Октября.</li>
<li>Напишите запрос который сосчитал бы число различных не-NULL значений поля city в таблице Заказчиков.</li>
<li>Напишите запрос который выбрал бы нименьшую сумму для каждого заказчика.</li>
<li>Напишите запрос который бы выбирал заказчиков в алфавитном порядке, чьи имена начинаются с буквы G.</li>
<li>Напишите запрос который выбрал бы высшую оценку в каждом городе.</li>
<li>Напишите запрос который сосчитал бы число заказчиков регистрирующих каждый день свои порядки. (Если продавец имел более одного порядка в данный день, он должен учитываться только один раз.)</li>
</ul>
<h2 id="глава-7-формирование-выводов-запросов">Глава 7. ФОРМИРОВАНИЕ ВЫВОДОВ ЗАПРОСОВ</h2>
<p>ЭТА ГЛАВА РАСШИРИТ ВАШИ ВОЗМОЖНОСТИ в работе с выводом который производит запрос. Вы узнаете как вставлять текст и константы между выбранных полей, как использовать выбранные поля в математических выражениях, чьи результаты затем становятся выводом, и как сделать чтобы ваши значения выводились в определенном порядке. Эта последняя особенность включена, чтобы упорядочивать ваш вывод по любым столбцам, любым полученным значениям этого столбца, или по обеим.</p>
<h3 id="строки-и-выражения">СТРОКИ И ВЫРАЖЕНИЯ</h3>
<p>Большинство основанных на SQL баз данных предоставляют специальные средства позволяющие Вам совершенствовать вывод ваших запросов. Конечно, они претерпевают значительные изменения от программы к программе, и их обсуждение здесь не входит в наши задачи, однако, имеются пять особенностей созданых в стандарте SQL которые позволяют вам делать больше чем просто вывод значений полей и агрегатных данных.</p>
<h3 id="скалярное-выражение-с-помощью-выбранных-полей">СКАЛЯРНОЕ ВЫРАЖЕНИЕ С ПОМОЩЬЮ ВЫБРАННЫХ ПОЛЕЙ</h3>
<p>Предположим что вы хотите выполнять простые числовые вычисления данных чтобы затем помещать их в форму больше соответствующую вашим потребностям. SQL позволяет вам помещать скалярные выражения и константы среди выбраных полей. Эти выражения могут дополнять или замещать поля в предложениях SELECT, и могут включать в себя одно или более выбранных полей. Например, вы можете пожелать, представить комиссионные вашего продавца в процентном отношении а не как десятичные числа. Просто достаточно:</p>
<pre><code>SELECT snum, sname, city, comm * 100
FROM Salespeople;
</code></pre>
<p>Вывод из этого запроса показывается в Таблице 7.1.</p>
<h3 id="столбцы-вывода">СТОЛБЦЫ ВЫВОДА</h3>
<p>Последний столбец предшествующего примера непомечен( т.е. без наименования), потому что это - столбец вывода. Столбцы вывода - это столбцы данных созданные запросом способом, иным чем просто извлечение их из таблицы. Вы создаете их всякий раз, когда вы используете агрегатные</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, sname, city, comm * 100 FROM Salespeople;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>  </th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   12.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   13.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   11.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   15.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   10.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 7.1: Помещение выражения в вашем запросе функции, константы, или выражения в предложении SELECT запроса. Так как имя столбца - один из атрибутов таблицы, столбцы которые приходят не из таблиц не имеют никаких имен. Другими словами непомеченные, столбцы вывода могут обрабатываться также как и столбцы извлеченные из таблиц, почти во всех ситуациях.</p>
<h3 id="помещение-текста-в-вашем-выводе-запроса">ПОМЕЩЕНИЕ ТЕКСТА В ВАШЕМ ВЫВОДЕ ЗАПРОСА</h3>
<p>Символ 'A', когда ничего не значит сам по себе, - является констан той, такой например как число 1. Вы можете вставлять константы в предложение SELECT запроса, включая и текст. Однако символьные константы, в отличие от числовых констант, не могут использоваться в выражениях.
Вы можете иметь выражение 1 + 2 в вашем предложении SELECT, но вы не можете использовать выражение типа 'A' + 'B'; это приемлемо только если мы имеем в виду что 'A' и 'B' это просто буквы, а не переменные и не символы.
Тем ни менее, возможность вставлять текст в вывод ваших запросов очень удобная штука.
Вы можете усовершенствовать предыдущий пример представив комиссионные как проценты со знаком процента (%). Это даст вам возможность помещать в вывод такие единицы как символы и комментарии, как например в следующем примере (вывод показывается в Таблице 7.2 )</p>
<pre><code>SELECT snum, sname, city, ' % ', comm * 100
FROM Salespeople;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, sname, city, '%' comm * 100
FROM Salespeople;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th> </th>
<th>  </th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   %<br style="margin: 0px; padding: 0px;"></td>
<td>   12.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   %<br style="margin: 0px; padding: 0px;"></td>
<td>   13.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   %<br style="margin: 0px; padding: 0px;"></td>
<td>   11.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   %<br style="margin: 0px; padding: 0px;"></td>
<td>   15.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   %<br style="margin: 0px; padding: 0px;"></td>
<td>   10.000000<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 7.2: Вставка символов в ваш вывод
Обратите внимание что пробел перед процентом вставляется как часть строки. Эта же самая особенность может использоваться чтобы маркировать вывод вместе с вставляемыми комментариями. Вы должны помнить, что этот же самый комментарий будет напечатан в каждой строке вывода, а не просто один раз для всей таблицы. Предположим что вы генерируете вывод для отчета который бы указывал число порядков получаемых в течение каждого дня. Вы можете промаркировать ваш вывод (см. Таблицу 7.3 ) сформировав запрос следующим образом:</p>
<pre><code>SELECT ' For ', odate, ', there are ',
COUNT (DISTINCT onum ), 'orders.'
FROM Orders
GROUP BY odate;
</code></pre>
<p>Грамматической некорректности вывода, на 5 Октября, невозможно избежать не создав запроса, еще более сложного чем этот. (Вы будете должны использовать два запроса с UNION, который</p>
<p>SQL Execution Log</p>
<pre><code>SELECT 'For', odate, ', ' there are ' ,
COUNT (DISTINCT onum), ' orders '
FROM Orders GROUP BY odate;
</code></pre>
<table>
<thead>
<tr>
<th>   odate</th>
<th>  </th>
<th>  </th>
<th> </th>
<th>  </th>
</tr>
</thead>
<tbody>
<tr>
<td>   For<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990 ,<br style="margin: 0px; padding: 0px;"></td>
<td>   there are<br style="margin: 0px; padding: 0px;"></td>
<td>   5<br style="margin: 0px; padding: 0px;"></td>
<td>   orders.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   For<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990 ,<br style="margin: 0px; padding: 0px;"></td>
<td>   there are<br style="margin: 0px; padding: 0px;"></td>
<td>   2<br style="margin: 0px; padding: 0px;"></td>
<td>   orders.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   For<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990 ,<br style="margin: 0px; padding: 0px;"></td>
<td>   there are<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
<td>   orders.<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   For<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990 ,<br style="margin: 0px; padding: 0px;"></td>
<td>   there are<br style="margin: 0px; padding: 0px;"></td>
<td>   2<br style="margin: 0px; padding: 0px;"></td>
<td>   orders.<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 7.3: Комбинация текста, значений поля, и агрегатов</p>
<p>мы будем описывать в Главе 14. ) Как вы можете видеть, одиночный неизменный комментарий для каждой строки таблицы может быть очень полезен, но имеет ограничения. Иногда изящнее и полезнее, произвести один ком ментарий для всего вывода в целом, или производить свой собственный комментарии для каждой строки.
Различные программы использующие SQL часто обеспечивают специальные средства типа генератора отчетов( например Report Writer), которые разработаны чтобы форматировать и совершенствовать вывод. Вложенный SQL может также эксплуатировать возможности того языка в который он вложен. SQL сам по себе интересен прежде всего при операциях с данными. Вывод, по существу, это информация, и программа использующая SQL может часто использовать эту информацию и помещать ее в более привлекательную форму. Это, однако, вне сферы самой SQL.</p>
<h3 id="упорядочение-вывода-полей">УПОРЯДОЧЕНИЕ ВЫВОДА ПОЛЕЙ</h3>
<p>Как мы подчеркивали, таблицы - это неупорядоченные наборы данных, и данные которе выходят из их, не обязательно появляются в какой-то определенной последовательности. SQL использует команду ORDER BY чтобы позволять вам упорядочивать ваш вывод. Эта команда упорядочивает вывод запроса согласно значениям в том или ином количестве выбранных столбцов. Многочисленые столбцы упорядочиваются один внутри другого, также как с GROUP BY, и вы можете определять возрастание (ASC ) или убывание (DESC ) для каждого столбца. По умолчанию установлено - возростание. Давайте рассмотрим нашу таблицу порядка приводимую в порядок с помощью номера заказчика (обратите внимание на значения в cnum столбце):</p>
<pre><code>SELECT *
FROM Orders
ORDER BY cnum DESC;
</code></pre>
<p>Вывод показывается в Рисунке 7.4.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Orders ORDER BY cnum DESC;
</code></pre>
<table>
<thead>
<tr>
<th>   onum</th>
<th>   amt</th>
<th>   odate</th>
<th>   cnum</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   18.69<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3006<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3002<br style="margin: 0px; padding: 0px;"></td>
<td>   1900.10<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3008<br style="margin: 0px; padding: 0px;"></td>
<td>   4723.00<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3011<br style="margin: 0px; padding: 0px;"></td>
<td>   9891.88<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3005<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2003<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3003<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 7. 4: Упорядочение вывода с помощью убывания поля
УПОРЯДОЧЕНИЕ С ПОМОЩЬЮ МНОГОЧИСЛЕНЫХ СТОЛБЦОВ
Мы можем также упорядочивать таблицу с помощью другого столбца, например с помощью поля amt, внутри упорядочения поля cnum. (вывод показан в Таблице 7.5 ):</p>
<pre><code>SELECT *
FROM Orders
ORDER BY cnum DESC, amt DESC;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Orders
ORDER BY cnum DESC, amt DESC;
</code></pre>
<table>
<thead>
<tr>
<th>   onum</th>
<th>   amt</th>
<th>   odate</th>
<th>   cnum</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   3006<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   18.69<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3002<br style="margin: 0px; padding: 0px;"></td>
<td>   1900.10<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3011<br style="margin: 0px; padding: 0px;"></td>
<td>   9891.88<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3008<br style="margin: 0px; padding: 0px;"></td>
<td>   4723.00<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3005<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2003<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3003<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 7.5: Упорядочение вывода с помощью многочисленых полей</p>
<p>Вы можете использовать ORDER BY таким же способом сразу с любым числом столбцов. Обратите внимание что, во всех случаях, столбцы которые упорядочиваются должны быть указаны в выборе SELECT. Это - требование ANSI которые в большинстве, но не всегда, предписано системе. Следующая команда, например, будет запрещена:</p>
<pre><code>SELECT cname, city
FROM Customers
GROUP BY cnum;
</code></pre>
<p>Так как поле cnum не было выбранным полем, GROUP BY не cможет найти его чтобы использовать для упорядочения вывода. Даже если ваша система позволяет это, смысл упорядочения не будет понятен из вывода, так что включение (в предложение SELECT) всех столбцов, используемых в предложении ORDER BY, в принципе желательно.</p>
<h3 id="упорядочение-агрегатных-групп">УПОРЯДОЧЕНИЕ АГРЕГАТНЫХ ГРУПП</h3>
<p>ORDER BY может кроме того, использоваться с GROUP BY для упорядочения групп. Если это так, то ORDER BY всегда приходит последним. Вот - пример из последней главы с добавлением предложения ORDER BY. Перед сгруппированием вывода, порядок групп был произвольным; и мы, теперь, заставим группы размещаться в последовательности:</p>
<pre><code>SELECT snum, odate, MAX (amt)
FROM Orders
GROUP BY snum, odate
GROUP BY snum;
</code></pre>
<p>Вывод показывается в Таблице 7.6.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, odate, MAX (amt) FROM Orders
GROUP BY snum, odate ORDER BY snum ;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   odate</th>
<th>   amt</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   767.19<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   4723.00<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   9891.88<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   5160.45<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   75.75<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1309.95<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1713.23<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1900.10<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 7.6: Упорядочение с помощью группы
Так как мы не указывали на возрастание или убывание порядка, возрастание используется по умолчанию.</p>
<h3 id="упорядочение-вывода-по-номеру-столбца">УПОРЯДОЧЕНИЕ ВЫВОДА ПО НОМЕРУ СТОЛБЦА</h3>
<p>Вместо имен столбца, вы можете использовать их порядковые номера для указания поля используемого в упорядочении вывода. Эти номера могут ссылаться не на порядок столбцов в таблице, а на их порядок в выводе.
Другими словами, поле упомянутое в предложении SELECT первым, для ORDER BY - это поле 1, независимо от того каким по порядку оно стоит в таблице. Например, вы можете использовать следующую команду чтобы увидеть определенные поля таблицы Продавцов, упорядоченными в порядке убывания к наименьшему значению комиссионных (вывод показывается в Таблице7.7 ):</p>
<pre><code>SELECT sname, comm
FROM Salespeople
GROUP BY 2 DESC;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT sname, comm FROM Salespeople
ORDER BY 2 DESC;
</code></pre>
<table>
<thead>
<tr>
<th>   sname</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   0.17<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   0.13<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   0.15<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 7. 7: Упорядочение использующее номера
Одна из основных целей этой возможности ORDER BY - дать вам возможность использовать GROUP BY со столбцами вывода также как и со столбцами таблицы. Столбцы производимые агрегатной функцией, константы, или выражения в предложении SELECT запроса, абсолютнопригодны для использования с GROUP BY, если они ссылаются к ним с помощью номера. Например, давайте сосчитаем порядки каждого из наших продавцов, и выведем результаты в убывающем порядке, как показано в Таблице 7.8:</p>
<pre><code>SELECT snum, COUNT (DISTINCT onum )
FROM Orders
GROUP BY snum
ORDER BY 2 DESC;
</code></pre>
<p>SQL Execution Log
SELECT snum, odate, MAX (amt) FROM Orders
GROUP BY snum ORDER BY 2 DESC;</p>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   odate</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   3<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   3<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   2<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>аблица 7.8: Упорядочение с помощью столбца вывода
В этом случае, вы должны использовать номер столбца, так как столбец вывода не имеет имени; и вы не должны использовать саму агрегатную функцию. Строго говоря по правилам ANSI SQL, следующее не будет работать, хотя некоторые системы и пренебрегают этим требованием:</p>
<pre><code>SELECT snum, COUNT (DISTINCT onum )
FROM Orders
GROUP BY snum
GROUP BY COUNTОМ (DISTINCT onum ) DESC;
</code></pre>
<p>Это будет отклонено большинством систем!</p>
<h3 id="упорядочение-с-помощью-опретора-null">УПОРЯДОЧЕНИЕ С ПОМОЩЬЮ ОПРЕТОРА NULL</h3>
<p>Если имеются пустые значения (NULL) в поле которое вы используете для упорядочивания вашего вывода, они могутут или следовать или предшествовать каждому другому значению в поле. Это - возможность которую ANSI оставил для индивидуальных программ. Данная программа использует ту или иную форму.</p>
<h3 id="резюме-6">РЕЗЮМЕ</h3>
<p>В этой главе, вы изучили как заставить ваши запросы делать больше, чем просто выводить значения полей или объединять функциональные данные таблиц. Вы можете использовать поля в выражениях: например, вы можете умножить числовое поле на 10 или даже умножить его на другое числовое поле. Кроме того, вы можете помещать константы, включая и символы, в ваш вывод, что позволяет вам помещать текст непосредственно в запрос и получать его в выводе вместе с данными таблицы.
Это дает вам возможность помечать или объяснять ваш вывод различными способами.
Вы также изучили как упорядочивать ваш вывод. Даже если таблица сама по себе остается неупорядоченной, предложение ORDER BY дает вам возможность управлять порядком вывода строк данного запроса. Вывод запроса может быть в порядке возрастания или убывания, и столбцы могут быть вложенными один внутрь другого.
Понятие выводимых столбцов объяснялось в этой главе. Вы теперь знаете что выводимые столбцы можно использовать чтобы упорядочивать вывод запроса, но эти столбцы - без имени, и следовательно должны опреде ляться их порядковым номером в предложении ORDER BY.
Теперь, когда вы увидели что можно делать с выводом запроса основанного на одиночной таблице, настало время чтобы перейти к возможностям улучшенного запроса и узнать как сделать запрос любого числа таблиц в одной команде, определив связи между ними как вы это обычно делали.
Это будет темой Главы 8.</p>
<h3 id="работа-с-sql-3">РАБОТА С SQL</h3>
<ul>
<li>Предположим что каждый продавец имеет 12% комиссионных. Напишите запрос к таблице Порядков который мог бы вывести номер порядка, номер продавца, и сумму комиссионных продавца для этого порядка.</li>
<li>Напишите запрос к таблице Заказчиков который мог бы найти высшуюоценку в каждом городе. Вывод должен быть в такой форме: For the city (city), the highest rating is: (rating).</li>
<li>Напишите запрос который выводил бы список заказчиков в нисходящемпорядке. Вывод поля оценки( rating ) должден сопровождаться именем закзчика и его номером.</li>
<li>Напишите запрос который бы выводил общие порядки на каждый день и помещал результаты в нисходящем порядке.</li>
</ul>
<h2 id="глава-8-запрашивание-многочисленых-таблиц-также-как-одной">Глава 8. ЗАПРАШИВАНИЕ МНОГОЧИСЛЕНЫХ ТАБЛИЦ ТАКЖЕ КАК ОДНОЙ</h2>
<p>ДО ЭТОГО, КАЖДЫЙ ЗАПРОС КОТОРЫЙ МЫ ИССЛЕДОВАЛИ основывался на одиночной таблице. В этой главе, вы узнаете как сделать запрос любого числа таблиц с помощью одной команды. Это - чрезвычайно мощное средство потому что оно не только объединяет вывод из многочисленых таблиц, но и определяет связи между ними. Вы обучитесь различным формам которые могут использовать эти связи, а также устанавливать и использовать их чтобы удовлетворять возможным специальным требованиям.</p>
<h3 id="объединение-таблиц">ОБЪЕДИНЕНИЕ ТАБЛИЦ</h3>
<p>Одна из наиболее важных особенностей запросов SQL - это их способность определять связи между многочислеными таблицами и выводить информацию из них в терминах этих связей, всю внутри одной команды. Этот вид операции называется - объединением, которое является одним из видов операций в реляционных базах данных. Как установлено в Главе 1, главное в реляционном подходе это связи которые можно создавать между позициями данных в таблицах. Используя обьединения, мы непосредственно связываем информацию с любым номером таблицы, и таким образом способныоздавать связи между сравнимыми фрагментами данных. При обьединении, таблицы представленые списком в предложении FROM запроса, отделяются запятыми. Предикат запроса может ссылаться к любому столбцу любой связанной таблицы и, следовательно, может использоваться для связи между ими. Обычно, предикат сравнивает значения в столбцах различных таблиц чтобы определить, удовлетворяет ли WHERE установленному условию.</p>
<h3 id="имена-таблиц-и-столбцов">ИМЕНА ТАБЛИЦ И СТОЛБЦОВ</h3>
<p>Полное имя столбца таблицы фактически состоит из имени таблицы, сопровождаемого точкой и затем именем столбца. Имеются несколько примеров имен:</p>
<pre><code>Salespeople.snu
Salespeople.city
Orders.odate
</code></pre>
<p>До этого, вы могли опускать имена таблиц потому что вы запрашивали только одну таблицу одновременно, а SQL достаточно интелектуален чтобы присвоить соответствующий префикс, имени таблицы. Даже когда вы делаете запрос многочисленых таблиц, вы еще можете опускать имена таблиц, если все ее столбцы имеют различные имена. Но это не всегда так бывает. Например, мы имеем две типовые таблицы со столбцами называемыми city.
Если мы должны связать эти столбцы( кратковременно ), мы будем должны указать их с именами Salespeople.city или Customers.city, чтобы SQL мог их различать.</p>
<h3 id="создание-обьединения">СОЗДАНИЕ ОБЬЕДИНЕНИЯ</h3>
<p>Предположим что вы хотите поставить в соответствии вашему продавцу ваших заказчиков в городе в котором они живут, поэтому вы увидите все комбинации продавцов и заказчиков для этого города. Вы будете должны брать каждого продавца и искать в таблице Заказчиков всех заказчиков того же самого города. Вы могли бы сделать это, введя следующую команду (вывод показывается в Таблице 8.1 ):</p>
<pre><code>SELECT Customers.cname, Salespeople.sname,
Salespeople.city
FROM Salespeople, Customers
WHERE Salespeople.city=Customers.city;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT Customers.cname, Salespeople.sname, Salespeople.city
FROM Salespeople, Customers WHERE Salespeople.city=Customers.city
</code></pre>
<table>
<thead>
<tr>
<th>   cname</th>
<th>   cname</th>
<th>   city</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Liu<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 8.1: Объединение двух таблиц
Так как это поле city имеется и в таблице Продавцов и таблице Заказчиков, имена таблиц должны использоваться как префиксы. Хотя это необходимо только когда два или более полей имеют одно и то же имя, в любом случае это хорошая идея включать имя таблицы в обьединение для лучшего понимания и непротиворечивости. Несмотря на это, мы будем, в наших примерах далее, использовать имена таблицы только когда необходимо, так что будет ясно, когда они необходимы а когда нет.
Что SQL в основном делает в обьединении - так это исследует каждую комбинацию строк двух или более возможных таблиц, и проверяет эти комбинации по их предикатам. В предыдущем примере, требовалась строка продавца Peel из таблицы Продавцов и объединение ее с каждой строкой таблицы Пользователей, по одной в каждый момент времени. Если комбинация производит значение которое делает предикат верным, и если поле city из строк таблиц Заказчика равно London, то Peel - это то запрашиваемое значение которое комбинация выберет для вывода. То же самое будет затем выполнено для каждого продавца в таблице Продавцов (у некоторых из которых небыло никаких заказчиков в этих городах).</p>
<h3 id="объединение-таблиц-через-справочную-целостность">ОБЪЕДИНЕНИЕ ТАБЛИЦ ЧЕРЕЗ СПРАВОЧНУЮ ЦЕЛОСТНОСТЬ</h3>
<p>Эта особенность часто используется просто для эксплуатации связей встроенных в базу данных. В предыдущем примере, мы установили связь между двумя таблицами в обьединении. Это прекрасно. Но эти таблицы, уже были соединены через snum поле. Эта связь называется состоянием справочной целостности, как мы уже говорили в Главе 1. Используя обьединение можно извлекать данные в терминах этой связи. Например, чтобы показать имена всех заказчиков соответствующих продавцам которые их обслуживают, мы будем использовать такой запрос:</p>
<pre><code>SELECT Customers.cname, Salespeople.sname
FROM Customers, Salespeople
WHERE Salespeople.snum=Customers.snum;
</code></pre>
<p>Вывод этого запроса показывается в Таблица 8.2.
Это - пример обьединения, в котором столбцы используются для определения предиката запроса, и в этом случае, snum столбцы из обеих таблиц, удалены из вывода. И это прекрасно. Вывод показывает какие заказчики каким продавцом обслуживаются; значения поля snum которые устанавливают связь - отсутствуют. Однако если вы введете их в вывод, то вы должны или удостовериться что вывод понятен сам по себе или обеспечить коментарий к данным при выводе.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT Customers.cname, Salespeople.sname,
FROM Salespeople, Customers
WHERE Salespeople.snum=Customers.snum
</code></pre>
<table>
<thead>
<tr>
<th>   cname</th>
<th>   sname</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Giovanni<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Liu<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Grass<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 8.2: Объединение продавцов с их заказчикам</p>
<h3 id="объединения-таблиц-по-равенству-значений-в-столбцах-и-другие-виды-объединений">ОБЪЕДИНЕНИЯ ТАБЛИЦ ПО РАВЕНСТВУ ЗНАЧЕНИЙ В СТОЛБЦАХ И ДРУГИЕ ВИДЫ ОБЪЕДИНЕНИЙ</h3>
<p>Обьединения которые используют предикаты основанные на равенствах называются - объединениями по равенству. Все наши примеры в этой главе до настоящего времени, относились именно к этой категории, потому что все условия в предложениях WHERE базировались на математических выражениях использующих знак равно (=). Строки 'city='London' и 'Salespeople.snum=Orders.snum ' - примеры таких типов равенств найденных в предикатах. Объединения по равенству - это вероятно наиболее общий вид объединения, но имеются и другие. Вы можете, фактически, использовать любой из реляционных операторов в обьединении. Здесь показан пример другого вида объединения (вывод показывается в Таблице 8.3):</p>
<pre><code>SELECT sname, cname
FROM Salespeople, Customers
WHERE sname &lt; cname
AND rating &lt; 200;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT sname, cname FROM Salespeople, Customers
WHERE sname &lt; cname AND rating &lt; 200;
</code></pre>
<table>
<thead>
<tr>
<th>   sname</th>
<th>   cname</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 8.3: Обьединение основанное на неравенстве
Эта команда не часто бывает полезна. Она воспроизводит все комбинации имени продавца и имени заказчика так, что первый предшествует последнему в алфавитном порядке, а последний имеет оценку меньше чем 200.
Обычно, вы не создаете сложных связей подобно этой, и, по этой причине, вы вероятно будете строить наиболее общие объединения по равенству, но вы должны хорошо знать и другие возможности.</p>
<h3 id="объединение-более-двух-таблиц">ОБЪЕДИНЕНИЕ БОЛЕЕ ДВУХ ТАБЛИЦ</h3>
<p>Вы можете также создавать запросы объединяющие более двух таблиц.
Предположим что мы хотим найти все порядки заказчиков не находящихся в тех городах где находятся их продавцы.Для этого необходимо связать все три наши типовые таблицы (вывод показывается в Таблице 8.4 ):</p>
<pre><code>SELECT onum, cname, Orders.cnum, Orders.snum
FROM Salespeople, Customers,Orders
WHERE Customers.city &lt; &gt; Salespeople.city
AND Orders.cnum=Customers.cnum
AND Orders.snum=Salespeople.snum;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT onum, cname, Orders.cnum, Orders.snum
FROM Salespeople, Customers, Orders
WHERE Customers.city &lt; &gt; Salespeople.city
AND Orders.cnum=Customers.cnum
AND Orders.snum=Salespeople.snum;
</code></pre>
<table>
<thead>
<tr>
<th>   onum</th>
<th>   cname</th>
<th>   cnum</th>
<th>   snum</th>
</tr>
</thead>
<tbody>
<tr>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3002<br style="margin: 0px; padding: 0px;"></td>
<td>   Pereira<br style="margin: 0px; padding: 0px;"></td>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3006<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   Giovanni<br style="margin: 0px; padding: 0px;"></td>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   Grass<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   Grass<br style="margin: 0px; padding: 0px;"></td>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 8. 4: Объединение трех таблиц
Хотя эта команда выглядит скорее как комплексная, вы можете следовать за логикой, просто проверяя - что заказчики не размещены в тех городах где размещены их продавцы (совпадение двух snum полей ), и что перечисленные порядки - выполнены с помощью этих заказчиков( совпадение порядков с полями cnum и snum в таблице Порядков ).</p>
<h3 id="резюме-7">РЕЗЮМЕ</h3>
<p>Теперь вы больше не ограничиваетесь просмотром одной таблицы в каждый момент времени. Кроме того, вы можете делать сложные сравнения между любыми полями любого числа таблиц и использовать полученные результаты чтобы решать какую информацию вы бы хотели видеть. Фактически, эта методика настолько полезна для построения связей, что она часто используется для создания их внутри одиночной таблицы. Это будет правильным: вы сможете объединить таблицу с собой, а это очень удобная вещь.
Это будет темой Главы 9.</p>
<h3 id="работа-с-sql-4">РАБОТА С SQL</h3>
<ul>
<li>Напишите запрос который бы вывел список номеров порядков сопровождающихся именем заказчика который создавал эти порядки.</li>
<li>Напишите запрос который бы выдавал имена продавца и заказчика для каждого порядка после номера порядков.</li>
<li>Напишите запрос который бы выводил всех заказчиков обслуживаемых продавцом с комиссионными выше 12% . Выведите имя заказчика, имя продавца, и ставку комиссионных продавца.</li>
<li>Напишите запрос который вычислил бы сумму комиссионных продавца для каждого порядка заказчика с оценкой выше 100.</li>
</ul>
<h2 id="глава-14-использование-предложения-union">Глава 14. ИСПОЛЬЗОВАНИЕ ПРЕДЛОЖЕНИЯ UNION</h2>
<p>В ПРЕДШЕСТВУЮЩИХ ГЛАВАХ, МЫ ОБСУЖДАЛИ различные способы которыми запросы могут помещаться один внутрь другого. Имеется другой способ объединения многочисленых запросов - то-есть формирование их в объединение. В этой главе, вы научитесь использованию предложения UNION в SQL. UNION отличается от подзапросов тем что в нем ни один из двух (или больше ) запросов не управляются другим запросом. Все запросы выполняются независимо друг от друга, а уже вывод их - обьединяется.</p>
<h3 id="объединение-многочисленных-запросов-в-один">ОБЪЕДИНЕНИЕ МНОГОЧИСЛЕННЫХ ЗАПРОСОВ В ОДИН</h3>
<p>Вы можете поместить многочисленые запросы вместе и объединить их вывод используя предложение UNION. Предложение UNION обьединяет вывод двух или более SQL запросов в единый набор строк и столбцов. Например чтобы получить всех продавцов и заказчиков размещенных в Лондоне и вывести их как единое целое вы могли бы ввести:</p>
<pre><code>SELECT snum, sname
FROM Salespeople
WHERE city='London'
</code></pre>
<h3 id="union">UNION</h3>
<pre><code>SELECT cnum, cname
FROM Customers
WHERE city='London';
</code></pre>
<p>и получить вывод показанный в Таблице 14.1.</p>
<p>Как вы можете видеть, столбцы выбранные двумя командами выведены так как если она была одна. Заголовки столбца исключены, потому что ни один из столбцов выведенных объединением, не был извлечен непосредственно из только одной таблицы. Следовательно все эти столбцы вывода не имеют никаких имен (смотрите Главу 7 обсуждающую вывод столбцов ).
Кроме того обратите внимание, что только последний запрос заканчивается точкой с запятой. Отсутствие точки с запятой дает понять SQL, что имеется еще одно или более запросов.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, sname FROM Salespeople WHERE city='London'
UNION SELECT cnum, cname FROM Customers
WHERE city='London';
</code></pre>
<table>
<thead>
<tr>
<th>   1001</th>
<th>   Peel</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   Climens<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 14.1: Формирование объединения из двух запросов</p>
<h3 id="когда-вы-можете-делать-объединение-между-запросами">КОГДА ВЫ МОЖЕТЕ ДЕЛАТЬ ОБЪЕДИНЕНИЕ МЕЖДУ ЗАПРОСАМИ?</h3>
<p>Когда два (или более ) запроса подвергаются объединению, их столбцы вывода должны быть совместимы для объединения. Это означает, что каждый запрос должен указывать одинаковое число столбцов и в том же порядке что и первый, второй, третий, и так далее, и каждый должен иметь тип, совместимый с каждым. Значение совместимости типов - меняется.
ANSI следит за этим очень строго и поэтому числовые поля должны иметь одинаковый числовой тип и размер, хотя некоторые имена испрользуемые ANSI для этих типов являются - синонимами. (Смотрите Приложение B для подробностей об ANSI числовых типах. ) Кроме того, символьные поля должны иметь одинаковое число символов (значение предначначенного номера, не обязательно такое же как используемый номер). Хорошо, что некоторые SQL программы обладают большей гибкостью чем это определяется ANSI. Типы не определенные ANSI, такие как DATA и BINARY, обычнодолжны совпадать с другими столбцами такого же нестандартного типа.
Длина строки также может стать проблемой. Большинство программ разрешают поля переменной длины, но они не обязательно будут использоваться с UNION. С другой стороны, некоторые программы (и ANSI тоже) требуют чтобы символьные поля были точно равной длины. В этих вопросах вы должны проконсультироваться с документацией вашей собственной программы.
Другое ограничение на совместимость - это когда пустые значения(NULL) запрещены в любом столбце объединения, причем эти значения необходимо запретить и для всех соответствующих столбцов в других запросах объединения. Пустые значения(NULL) запрещены с ограничением NOT NULL, которое будет обсуждаться в Главе 18. Кроме того, вы не можете использовать UNION в подзапросах, а также не можете использовать агрегатные функции в предложениии SELECT запроса в объединении. (Большинство программ пренебрегают этими ограничениями. )</p>
<h3 id="union-и-устранение-дубликатов">UNION И УСТРАНЕНИЕ ДУБЛИКАТОВ</h3>
<p>UNION будет автоматически исключать дубликаты строк из вывода. Это нечто несвойственное для SQL, так как одиночные запросы обычно содержат DISTINCT чтобы устранять дубликаты. Например запрос, чей вывод показывается в Таблице 14.2,</p>
<pre><code>SELECT snum, city
FROM Customers;
</code></pre>
<p>имеет двойную комбинацию значений (snum=1001, city=London ), потомучто мы не указали, чтобы SQL устранил дубликаты. Однако, если мы используем</p>
<p>SQL Execution Log</p>
<pre><code>SELECT snum, city FROM Customers;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   city</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Berlin<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 14.2: Одиночный запрос с дублированным выводом
UNION в комбинации этого запроса с ему подобным в таблице Продавцов, то эта избыточная комбинация будет устранена. Таблица 14.3 показывает вывод следующего запроса.</p>
<pre><code>SELECT snum, city
FROM Customers

UNION

SELECT snum, city
FROM Salespeople.;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>FROM Customers UNION SELECT snum, sity
FROM Salespeople;
</code></pre>
<table>
<thead>
<tr>
<th>   1001</th>
<th>   London</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Berlin<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 14.3: UNION устраняет двойной вывод</p>
<p>Вы можете получить нечто похожее (в некоторых программах SQL, используя UNION ALL вместо просто UNION, наподобии этого:</p>
<pre><code>SELECT snum, city
FROM Customers

UNION ALL

SELECT snum, city
FROM Salespeople;
</code></pre>
<h3 id="использование-строк-и-выражений-с-union">ИСПОЛЬЗОВАНИЕ СТРОК И ВЫРАЖЕНИЙ С UNION</h3>
<p>Иногда, вы можете вставлять константы и выражения в предложения SELECT используемые с UNION. Это не следует строго указаниям ANSI, но это полезная и необычно используемая возможность. Константы и выражения которые вы используете, должны встречать совместимые стандарты которые мы выделяли ранее. Эта свойство полезно, например, чтобы устанавливать комментарии указывающие какой запрос вывел данную строку.
Предположим что вы должны сделать отчет о том, какие продавцы производят наибольшие и наименьшие порядки по датам. Мы можем объединить два запроса, вставив туда текст чтобы различать вывод для каждого из них.</p>
<pre><code>SELECT a.snum, sname, onum, 'Highest on', odate
FROM (Salespeople a, Orders b
WHERE a.snum=b.snum
AND b.amt=
( SELECT MAX (amt)
FROM Orders c
WHERE c.odate=b.odate )

UNION

SELECT a.snum, (sname, (onum ' Lowest on', odate
FROM (Salespeople a, Orders b
WHERE a.snum=b.snum
AND b.amt=
( SELECT MIN (amt)
FROM Orders c
WHERE c.odate=b.odate );
</code></pre>
<p>Вывод из этой команды показывается в Таблице 14.4.</p>
<p>Мы должны были добавить дополнительный пробел в строку 'Lowest on', чтобы сделать ее совпадающей по длине со строкой 'Highest on'. Обратите внимание что Peel выбран при наличии и самого высокого и самого низкого (фактически он единственый ) порядка на 5 Октября. Так как вставляемые строки двух этих запросов различны, строки не будут устранены как дубликаты.</p>
<p>SQL Execution Log</p>
<pre><code>AND b.amt=( SELECT min (amt) FROM Orders c
WHERE c.odate=b.odate)
</code></pre>
<table>
<thead>
<tr>
<th>   1001</th>
<th>   Peel</th>
<th>   3008</th>
<th>   Highest on</th>
<th>   10/05/1990</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   3008<br style="margin: 0px; padding: 0px;"></td>
<td>   Lowest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   3011<br style="margin: 0px; padding: 0px;"></td>
<td>   Highest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   3005<br style="margin: 0px; padding: 0px;"></td>
<td>   Highest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   Lowest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   Lowest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   Highest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   Lowest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 14.4: Выбор наивысших и наинизших порядков, определяемых с помощью строк</p>
<h3 id="использование-union-с-order-by">ИСПОЛЬЗОВАНИЕ UNION С ORDER BY</h3>
<p>До сих пор, мы не оговаривали что данные многочисленых запросов будут выводиться в каком то особом порядке. Мы просто показывали вывод сначала из одного запроса а затем из другого. Конечно, вы не можете полагаться на вывод приходящий в произвольном порядке. Мы как раз сделаем так чтобы этот способ для выполнения примеров был более простым.
Вы можете, использовать предложение ORDER BY чтобы упорядочить вывод из объединения, точно так же как это делается в индивидуальных запросах. Давайте пересмотрим наш последний пример чтобы упорядочить имена с помощью их порядковых номеров. Это может внести противоречие, такое как повторение имени Peel в последней команде, как вы сможете увидеть из вывода показанного в Таблице 14.5.</p>
<pre><code>SELECT a.snum, sname, onum, 'Highest on', odate
FROM Salespeople a, Orders b
WHERE a.snum=b.snum
AND b.amt=
( SELECT MAX (amt)
FROM Orders c
WHERE c.odate=b.odate )

UNION
SELECT a.snum, (sname, (onum, 'Lowest on', odat
FROM Salespeople a, Orders b
WHEREa.snum=b.snum
 AND b.amt=
( SELECT MIN (amt)
FROM Orders c
WHERE c.odate=b.odate )

ORDER BY 3;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT min (amt) FROM Orders c
WHERE c.odate=b.odate) ORDER BY 3;
</code></pre>
<table>
<thead>
<tr>
<th>   1007</th>
<th>   Rifkin</th>
<th>   3001</th>
<th>   Lowest on</th>
<th>   10/03/1990</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   3005<br style="margin: 0px; padding: 0px;"></td>
<td>   Highest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/03/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   3007<br style="margin: 0px; padding: 0px;"></td>
<td>   Lowest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   3008<br style="margin: 0px; padding: 0px;"></td>
<td>   Highest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   3008<br style="margin: 0px; padding: 0px;"></td>
<td>   Lowest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/05/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   3009<br style="margin: 0px; padding: 0px;"></td>
<td>   Highest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/04/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   3010<br style="margin: 0px; padding: 0px;"></td>
<td>   Lowest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   3011<br style="margin: 0px; padding: 0px;"></td>
<td>   Highest on<br style="margin: 0px; padding: 0px;"></td>
<td>   10/06/1990<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 14.5: Формирование объединения с использованием ORDER BY
Пока ORDER BY используется по умолчанию, мы не должны его указывать.
Мы можем упорядочить наш вывод с помощью нескольких полей, одно внутри другого и указать ASC или DESC для каждого, точно также как мы делали это для одиночных запросов. Заметьте, что номер 3 в предложении ORDER BY указывает какой столбец из предложения SELECT будет упорядочен. Так как столбцы объединения - это столбцы вывода, они не имеют имен, и следовательно, должны определяться по номеру. Этот номер указывает на их место среди других столбцов вывода. (Смотрите Главу 7, обсуждающую столбцы вывода.)</p>
<h3 id="внешнее-объединение">ВНЕШНЕЕ ОБЪЕДИНЕНИЕ</h3>
<p>Операция которая бывает часто полезна - это объединение из двух запросов в котором второй запрос выбирает строки, исключенные первым. Наиболее часто, вы будете делать это, так чтобы не исключать строки которые не удовлетворили предикату при объединении таблиц. Это называется - внешним обьединением. Предположим что некоторые из ваших заказчиков еще не были назначены к продавцам. Вы можете захотеть увидеть имена и города всех ваших заказчиков, с именами их продавцов, не учитывая тех кто еще не был назначен. Вы можете достичь этого, формируя объединение из двух запросов, один из которых выполняет обьединение, а другой выбирает заказчиков с пустыми(NULL) значениями поля snum. Этот последний запрос должен вставлять пробелы в поля соответствующие полю sname в первом запросе. Как и раньше, вы можете вставлять текстовые строки в ваш вывод чтобы идентифицировать запрос который вывел данную строку. Использование этой методики во внешнем обьединении, дает возможность использовать предикаты для классификации, а не для исключения.
Мы использовали пример нахождения продавцов с заказчиками размещенными в их городах и раньше. Однако вместо просто выбора только этих строк, вы возможно захотите чтобы ваш вывод перечислял всех продавцов, и указывал тех, кто не имел заказчиков в их городах, и кто имел. Следующий запрос, чей вывод показывается в Таблице 14.6, выполнит это:</p>
<pre><code>SELECT Salespeople.snum, sname, cname, comm
FROM (Salespeople, Customers
WHERE Salespeople.city=Customers.city.

UNION

SELECT snum, sname, ' NO MATCH ', comm
FROM (Salespeople
WHERE NOT city=ANY
( SELECT city
FROM Customers )

ORDER BY 2 DESC;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>FROM Salespeople WHERE NOT city=ANYate)
( SELECT city FROM Customers) ORDER BY 2 DESC;
</code></pre>
<table>
<thead>
<tr>
<th>   1002</th>
<th>   Serres</th>
<th>   Cisneros</th>
<th>   0.1300</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   Liu<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1300<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   NO MATCH<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1500<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1200<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1200<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   Clemens<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1100<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   Hoffman<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1100<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   NO MATCH<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1000<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 14. 6: Внешнее обьединение</p>
<p>Строка 'NO MATCH' была дополнена пробелами, чтобы получить совпадение поля cname по длине (это не обязательно во всех реализациях SQL). Второй запрос выбирает даже те строки которые исключил первый. Вы можете также добавить комментарий или выражение к вашему запросу, ввиде дополнительного поля. Если вы сделаете это, вы будете должны добавить некоторый дополнительный комментарий или выражение, в той же самой позиции среди выбранных полей, для каждого запроса в операции объединения. Совместимость UNION предотвращает вас от добавления дополнительного поля для первого запроса, но не для второго. Имеется запрос который добавляет строки к выбранным полям, и указывает совпадает ли данный продавец с его заказчиком в его городе:</p>
<pre><code>SELECT a.snum, sname, a.city, ' MATCHED '
FROM Salespeople a, Customers b
WHERE a.city=b.city

UNION

SELECT snum, sname, city, 'NO MATCH'
FROM Salespeople
WHERE NOT city=ANY
( SELECT city
FROM Customers )

ORDER BY 2 DESC;
</code></pre>
<p>Таблица 14,7 показывает вывод этого запроса.</p>
<p>SQL Execution Log</p>
<pre><code>WHERE a.city=b.city UNION SELECT snum,sname,city, 'NO MATCH'
FROM Salespeople WHERE NOT city=ANYate)
( SELECT city FROM Customers) ORDER BY 2 DESC;
</code></pre>
<table>
<thead>
<tr>
<th>   1002</th>
<th>   Serres</th>
<th>   San Jose</th>
<th>   MATCHED</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barselona<br style="margin: 0px; padding: 0px;"></td>
<td>   NO MATCH<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   MATCHED<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   MATCHED<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   NO MATCH<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 14. 7: Внешнее обьединение с полем коментария
Это не полное внешнее объединение, так как оно включает только несовпадающие поля одной из объединяемых таблиц. Полное внешнеее объединение должно включать всех заказчиков имеющих и не имеющих продавцов в их городах. Такое условие будет более полным, как вы это сможете увидеть (вывод следующего запроса показан в Таблице 14,8) :</p>
<pre><code>SELECT snum, city, 'SALESPERSON - MATCH'
FROM Salespeople
WHERE NOT city=ANY
(SELECT city
FROM Customers)

UNION

SELECT snum, city, 'SALESPERSON - NO MATCH'
FROM Salespeople
WHERE NOT city=ANY
(SELECT city
FROM Customers))

UNION

(SELECT cnum, city, 'CUSTOMER - MATCHED'
FROM Customers
WHERE city=ANY
(SELECT city
FROM Salespeople)

UNION

SELECT cnum, city, 'CUSTOMER - NO MATCH'
FROM Customers
WHERE NOT city=ANY
(SELECT city
FROM Salespeople))

ORDER BY 2 DESC;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>FROM Salespeople) ORDER BY 2 DESC;
</code></pre>
<table>
<thead>
<tr>
<th>   2003</th>
<th>   San Jose</th>
<th>   CUSTOMER - MATCHED</th>
</tr>
</thead>
<tbody>
<tr>
<td>   2008<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   CUSTOMER - MATCHED<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   CUSTOMER - NO MATCH<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   CUSTOMER - NO MATCH<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   SALESPERSON - MATCHED<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
<td>   SALESPERSON - NO MATCH<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2001<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   CUSTOMER - MATCHED<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2006<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   CUSTOMER - MATCHED<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2004<br style="margin: 0px; padding: 0px;"></td>
<td>   Berlin<br style="margin: 0px; padding: 0px;"></td>
<td>   CUSTOMER - NO MATCH<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   SALESPERSON - MATCHED<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
<td>   SALESPERSON - NO MATCH<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 1.8: Полное внешнее обьединение
( Понятно, что эта формула использующая ANY - эквивалентна обьединению в предыдущем примере. )
Сокращенное внешнее обьединение с которого мы начинали, используется чаще чем этот последний пример. Этот пример, однако, имеет другой смысл. Всякий раз, когда вы выполняете объединение более чем двух запросов, вы можете использовать круглые скобки чтобы определить порядок оценки. Другими словами, вместо просто -</p>
<pre><code>query X UNION query Y UNION query Z;
</code></pre>
<p>вы должны указать, или</p>
<pre><code>( query X UNION query Y )UNION query Z;
</code></pre>
<p>или
query X UNION (query Y UNION query Z );</p>
<p>Это потому, что UNION и UNION ALL могут быть скомбинированны, чтобы удалять одни дубликаты, не удаляя других. Предложение -</p>
<pre><code>( query X UNION ALL query Y )UNION query Z;
</code></pre>
<p>не обязательно воспроизведет те же результаты что предложение -</p>
<pre><code>query X UNION ALL( query Y UNION query Z );
</code></pre>
<p>если двойные строки в нем, будут удалены.</p>
<h3 id="резюме-8">РЕЗЮМЕ</h3>
<p>Теперь вы знаете как использовать предложение UNION, которое дает возможность объединять любое число запросов в единое тело вывода. Если вы имеете ряд подобных таблиц - таблиц, содержащих похожую информацию, но принадлежащую разным пользователям и охватывающую различные особенности, возможно - что объединение сможет обеспечить простой способ для слияния и упорядочивания вывода. Аналогично, внешние обьединения дают вам новый способ использования условий, не для исключения вывода, а для его маркировки или обработки его частей, когда встречается условие отличающееся от того, которое не выполняется.
Этим заканчиваются наши главы о запросах. Вы теперь имеете довольно полное представление о поиске данных в SQL. Следующий шаг должен включать то, как значения вводятся в таблицы и как таблицы создаются с самого начала. Как вы увидете, запросы иногда используются внутри других типов команд, также хорошо как и сами по себе.</p>
<h3 id="работа-с-sql-5">РАБОТА С SQL</h3>
<ul>
<li>Создайте объединение из двух запросов которое показало бы имена, города, и оценки всех заказчиков. Те из них которые имеют поле rating=200 и более, должны кроме того иметь слова - &quot;Высокий Рейтинг&quot;, а остальные должны иметь слова &quot; Низкий Рейтинг &quot;.</li>
<li>Напишите команду которая бы вывела имена и номера каждого продавц и каждого заказчика которые имеют больше чем один текущий порядок. Результат представьте в алфавитном порядке.</li>
<li>Сформируйте объединение из трех запросов. Первый выбирает поля snum всех продавцов в San Jose; второй, поля cnum всех заказчиков в San Jose; и третий поля onum всех порядков на 3 Октября. Сохраните дубликаты между последними двумя запросами, но устраните любую избыточность вывода между каждым из их и самым первым. (Примечание: в данных типовых таблицах, не содержится никакой избыточности. Это только пример.)</li>
</ul>
<h2 id="глава-15-ввод-удаление-и-изменение-значений-полей">Глава 15. ВВОД, УДАЛЕНИЕ и ИЗМЕНЕНИЕ ЗНАЧЕНИЙ ПОЛЕЙ</h2>
<p>ЭТА ГЛАВА ПРЕДСТАВЛЯЕТ КОМАНДЫ КОТОРЫЕ управляют значениями представляемыми в таблице. Когда вы закончите эту главу, вы будете способны помещать строки в таблицу, удалять их, и изменять индивидуальные значения представленные в каждой строке.</p>
<p>Будет показано использование запросов в формировании полной группы строк для вставки, а также, как может использоваться предикат для управления изменения значений и удаления строк. Материал в этой главе составляет полный объем знаний показывающий, как создавать и управлять информацией в базе данных.
Более мощные способы проектирования предикатов будут обсуждены в следующей главе.</p>
<h3 id="команды-модификации-языка-dml">КОМАНДЫ МОДИФИКАЦИИ ЯЗЫКА DML</h3>
<p>Значения могут быть помещены и удалены из полей, тремя командами языка DML (Язык Манипулирования Данными ):</p>
<pre><code>INSERT (ВСТАВИТЬ),
UPDATE (МОДИФИЦИРОВАТЬ),
DELETE (УДАЛИТЬ).
</code></pre>
<p>Не смущайтесь, все они упоминались ранее в SQL, как команды модификации.
ВВОД ЗНАЧЕНИЙ
Все строки в SQL вводятся с использованием команды модификации INSERT. В самой простой форме, INSERT использует следующий синтаксис:</p>
<pre><code>INSERT INTO &lt;table name&gt;
VALUES (&lt;value&gt;, &lt;value&gt; . . .);
</code></pre>
<p>Так, например, чтобы ввести строку в таблицу Продавцов, вы можете использовать следующее условие:</p>
<pre><code>INSERT INTO Salespeople
VALUES (1001, 'Peel', 'London', .12);
</code></pre>
<p>Команды DML не производят никакого вывода, но ваша программа должна дать вам некоторое подтверждение того что данные были использованы.
Имя таблицы (в нашем случае - Salespeople (Продавцы)), должно быть предварительно определено, в команде CREATE TABLE (см. Главу 17 ), а каждое значение пронумерованное в предложении значений, должно совпадать с типом данных столбца, в который оно вставляется. В ANSI, эти значения не могут составлять выражений, что означает что 3 - это доступно, а выражение 2 + 1 - нет. Значения, конечно же, вводятся в таблицу в поименном порядке, поэтому первое значение с именем, автоматическми попадает в столбец 1, второе в столбец 2, на так далее.</p>
<h3 id="вставка-пустых-указателей-null">ВСТАВКА ПУСТЫХ УКАЗАТЕЛЕЙ (NULL)</h3>
<p>Если вам нужно ввести пустое значение(NULL), вы вводите его точно также как и обычное значение. Предположим, что еще не имелось поля city для мистера Peel. Вы можете вставить его строку со значением=NULL в это поле, следующим образом:</p>
<pre><code>INSERT INTO Salespeople
VALUES (1001, 'Peel', NULL, .12);
</code></pre>
<p>Так как значение NULL - это специальный маркер, а не просто символьное значение, он не включяется в одиночные кавычки.
ИМЕНОВАНИЕ СТОЛБЦА ДЛЯ ВСТАВКИ (INSERT)
Вы можете также указывать столбцы, куда вы хотите вставить значение имени. Это позволяет вам вставлять имена в любом порядке. Предположим что вы берете значения для таблицы Заказчиков из отчета выводимого на принтер, который помещает их в таком порядке: city, cname, и cnum, и для упрощения, вы хотите ввести значения в том же порядке:</p>
<pre><code>INSERT INTO Customers (city, cnamе, cnum)
VALUES ('London', 'Honman', 2001);
</code></pre>
<p>Обратите внимание что столбцы rating и snum - отсутствуют. Это значит, что эти строки автоматически установлены в значение - по умолчанию. По умолчанию может быть введено или значение NULL или другое значение определяемое как - по умолчанию. Если ограничение запрещает использование значения NULL в данном столбце, и этот столбец не установлен как по умолчанию, этот столбец должен быть обеспечен значением для любой команды INSERT которая относится к таблице( смотри Главу 18 для информации об ограничениях на NULL и на &quot;по умолчанию&quot; ).</p>
<h3 id="вставка-результатов-запроса">ВСТАВКА РЕЗУЛЬТАТОВ ЗАПРОСА</h3>
<p>Вы можете также использовать команду INSERT чтобы получать или выбирать значения из одной таблицы и помещать их в другую, чтобы использовать их вместе с запросом. Чтобы сделать это, вы просто заменяете предложение VALUES (из предыдущего примера) на соответствующий запрос:</p>
<pre><code>INSERT INTO Londonstaff
SELECT *
FROM Salespeople
WHERE city='London';
</code></pre>
<p>Здесь выбираются все значения произведенные запросом - то-есть все строки из таблицы Продавцов со значениями city=&quot;London&quot; - и помещаются в таблицу называемую Londonstaff. Чтобы это работало, таблица Londonstaff должна отвечать следующим условиям:</p>
<ul>
<li>Она должна уже быть создана командой CREATE TABLE.</li>
<li>Она должна иметь четыре столбца которые совпадают с таблицей Продавцов в терминах типа данных; то-есть первый, второй, и так далее, столбцы каждой таблицы, должны иметь одинаковый тип данных (причем они не должны иметь одинаковых имен ).</li>
</ul>
<p>Общее правило то, что всталяемые столбцы таблицы, должны совпадать со столбцами выводимыми подзапросом, в данном случае, для всей таблицы Продавцов.
Londonstaff - это теперь независимая таблица которая получила некоторые значения из таблицы Продавцов(Salespeople). Если значения в таблице Продавцов будут вдруг изменены, это никак не отразится на таблицеLondonstaff (хотя вы могли бы создать такой эффект, с помощью Представления( VIEW), описанного в Главе 20 ).
Так как или запрос или команда INSERT могут указывать столбцы по имени, вы можете, если захотите, переместить только выбранные столбцы а также переупорядочить только те столбцы которые вы выбрали. Предположим, например, что вы решили сформировать новую таблицу с именем Daytotals, которая просто будет следить за общим количеством долларов сумм приобретений упорядоченных на каждый день. Вы можете ввести эти данные независимо от таблицы Порядков, но сначала вы должны заполнить таблицу Daytotals информацией ранее представленной в таблице Порядков.
Понимая что таблица Поряжков охватывает последний финансовый год, а не только несколько дней, как в нашем примере, вы можете видеть преимущество использования следующего условия INSERT в подсчете и вводе значений</p>
<pre><code>INSERT INTO Daytotals (date, total)
SELECT odate, SUM (amt)
FROM Orders
GROUP BY odate;
</code></pre>
<p>Обратите внимание что, как предложено ранее, имена столбцов таблицы Порядков и таблицы Daytotals - не должны быть одинаковыми. Кроме того, если дата приобретения и общее количество - это единственые столбцы в таблице, и они находятся в данном порядке, их имена могут быть исключены из вывода из-за их очевидной простоты.
###\УДАЛЕНИЕ СТРОК ИЗ ТАБЛИЦ
Вы можете удалять строки из таблицы командой модификации - DELETE.
Она может удалять только введеные строки, а не индивидуальные значения полей, так что параметр поля является необязательным или недоступным.
Чтобы удалить все содержание таблицы Продавцов, вы можете ввести следующее условие:</p>
<h3 id="delete-from-salespeople">DELETE FROM Salespeople;</h3>
<p>Теперь когда таблица пуста ее можно окончательно удалить командой DROP TABLE (это объясняется в Главе 17 ).
Обычно, вам нужно удалить только некоторые определенные строки из таблицы. Чтобы определить какие строки будут удалены, вы используете предикат, так же как вы это делали для запросов. Например, чтобы удалить продавца Axelrod из таблицы, вы можете ввести</p>
<pre><code>DELETE FROM Salespeople
WHERE snum=1003;
</code></pre>
<p>Мы использовали поле snum вместо поля sname потому, что это лучшая тактика при использовании первичных ключей когда вы хотите чтобы действию подвергалась одна и только одна строка. Для вас - это аналогично действию первичного ключя.
Конечно, вы можете также использовать DELETE с предикатом который бы выбирал группу строк, как показано в этом примере:</p>
<pre><code>DELETE FROM Salespeople
WHERE city='London';
</code></pre>
<h3 id="изменение-значений-поля">ИЗМЕНЕНИЕ ЗНАЧЕНИЙ ПОЛЯ</h3>
<p>Теперь, когда вы уже можете вводить и удалять строки таблицы, вы должны узнать как изменять некоторые или все значения в существующей строке.
Это выполняется командой UPDATE. Эта команда содержит предложение UPDATE в которой указано имя используемой таблицы и предложение SET которое указывает на изменение которое нужно сделать для определенного столбца. Например, чтобы изменить оценки всех заказчиков на 200, вы можете ввести</p>
<pre><code>UPDATE Customers
SET rating=200;
</code></pre>
<h3 id="модифицирование-только-определенных-строк">МОДИФИЦИРОВАНИЕ ТОЛЬКО ОПРЕДЕЛЕННЫХ СТРОК</h3>
<p>Конечно, вы не всегда захотите указывать все строки таблицы для изменения единственного значения, так что UPDATE, наподобии DELETE, может брать предикаты. Вот как например можно выполнить изменение одинаковое для всех заказчиков продавца Peel (имеющего snum=1001 ):</p>
<pre><code>UPDATE Customers
SET rating=200
WHERE snum=1001;
</code></pre>
<h3 id="команда-update-для-многих-столбцов">КОМАНДА UPDATE ДЛЯ МНОГИХ СТОЛБЦОВ</h3>
<p>Однако, вы не должны, ограничивать себя модифицированием единственного столбца с помощью команды UPDATE. Предложение SET может назначать любое число столбцов, отделяемых запятыми. Все указанные назначения могут быть сделаны для любой табличной строки, но только для одной в каждый момент времени. Предположим, что продавец Motika ушел на пенсию, и мы хотим переназначить его номер новому продавцу:</p>
<pre><code>UPDATE Salespeople
SET sname='Gibson',city='Boston',comm=.10
WHERE snum=1004;
</code></pre>
<p>Эта команда передаст новому продавцу Gibson, всех текущих заказчиков бывшего продавца Motika и порядки, в том виде в котором они были скомпонованы для Motika с помощью поля snum. Вы не можете, однако, модифицировать сразу много таблиц в одной команде, частично потому, что вы не можете использовать префиксы таблицы со столбцами измененными предложением SET. Другими словами, вы не можете сказать - &quot;SET Salespeople.sname=Gibson&quot; в команде UPDATE, вы можете сказать только так - &quot;SET sname =Gibson&quot;.</p>
<h3 id="использование-выражений-для-модификации">ИСПОЛЬЗОВАНИЕ ВЫРАЖЕНИЙ ДЛЯ МОДИФИКАЦИИ</h3>
<p>Вы можете использовать скалярные выражения в предложении SET команды UPDATE, однако, включив его в выражение поля которое будет изменено. В этом их отличие от предложения VALUES команды INSERT, в котором выражения не могут использоваться; это свойство скалярных выражений весьма полезная особенность. Предположим, что вы решили удвоить комиссионные всем вашим продавцам. Вы можете использовать следующее выражение:</p>
<pre><code>UPDATE Salespeople
SET comm=comm * 2;
</code></pre>
<p>Всякий раз, когда вы ссылаетесь к указанному значению столбца в предложении SET, произведенное значение может получится из текущей строки, прежде в ней будут сделаны какие-то изменения с помощью команды UPDATE. Естественно, вы можете скомбинировать эти особенности, и сказать, - удвоить комиссию всем продавцам в Лондоне, таким предложением:</p>
<pre><code>UPDATE Salespeople
SET comm=comm * 2
WHERE city='London';
</code></pre>
<h3 id="модифицирование-пустыхnull-значений">МОДИФИЦИРОВАНИЕ ПУСТЫХ(NULL) ЗНАЧЕНИЙ</h3>
<p>Предложение SET - это не предикат. Он может вводить пустые NULL значения также как он вводил значения не используя какого-то специального синтаксиса (такого например как IS NULL). Так что, если вы хотите установить все оценки заказчиков в Лондоне в NULL, вы можете ввести следующее предложение:</p>
<pre><code>UPDATE customers
SET rating=NULL
WHERE city='London';
</code></pre>
<p>что обнулит все оценки заказчиков в Лондоне.</p>
<h3 id="резюме-9">РЕЗЮМЕ</h3>
<p>Теперь вы овладели мастерством управления содержанием вашей базы данных с помощью трех простых команд:</p>
<p><strong>INSERT</strong> - используемой чтобы помещать строки в базу данных;
<strong>DELETE</strong> - чтобы удалять их;
<strong>REFERENCES</strong> - чтобы изменять значения в уже вставленных строках.
Вы обучались использованию предиката с командами UPDATE и DELETE чтобы определять, на которую из строк будет воздействовать команда.
Конечно, предикаты как таковые - не значимы для INSERT, потому что обсуждаемая строка не существует в таблице до окончания выполнения команды INSERT. Однако, вы можете использовать запросы с INSERT, чтобы сразу помещать все наборы строк в таблицу. Причем это, вы можете делать со столбцами в любом порядке.
Вы узнали, что значения по умолчанию, могут помещаться в столбцы,если вы не устанавливаете это значение явно. Вы также видели использование стандартного значения по умолчанию, которым является NULL. Кроме того, вы поняли, что UPDATE может использовать выражение значения, тогда как INSERT не может.
Следующая глава расширит ваше познания, показав вам, как использовать подзапросы с этими командами. Эти подзапросы напоминают те, с которыми вы уже знакомы, но имеются некоторые специальные выводы и ограничения, когда подзапросы используются в командах DML, что мы будем обсуждать в Главе 16.</p>
<h3 id="работа-с-sql-6">РАБОТА С SQL</h3>
<p>Напишите команду которая бы поместила следующие значения, в их нижеуказанном порядке, в таблицу Продавцов:
city - San Jose,
name - Bianco,
comm - NULL,</p>
<ul>
<li>cnum - 1100.</li>
<li>Напишите команду которая бы удалила все порядки заказчика Clemens из таблицы Порядков.</li>
<li>Напишите команду которая бы увеличила оценку всех заказчиков в Риме на 100.</li>
<li>Продавец Serres оставил компанию. Переназначьте его заказчиков продавцу Motika.</li>
</ul>
<h2 id="глава-16-использование-подзапросов-с-командами-модификации">Глава 16. ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С КОМАНДАМИ МОДИФИКАЦИИ</h2>
<p>В ЭТОЙ ГЛАВЕ, ВЫ УЗНАЕТЕ КАК ИСПОЛЬЗОВАТЬ подзапросы в командах модификации. Вы найдете, что нечто подобное - вы уже видели при использовании подзапросов в запросах. Понимание, как подзапросы используются в командах SELECT, cделает их применение в командах модификации более уверенным, хотя и останутся некоторые вопросы.</p>
<p>Завершением команды SELECT является подзапрос, но не предикат, и поэтому его использование отличается от использования простых предикатов с командами модификации, которые вы уже выполняли ранеее с командами UPDATE и DELETE. Вы использовали простые запросы чтобы производить значения для INSERT, а теперь мы можем расширить эти запросы чтобы включять в них подзапросы.
Важный принцип который надо соблюдать при работе с командами модификации, состоит в том, что вы не можете в предложении FROM любого подзапроса, модифицировать таблицу к которой ссылаетесь с помощью основной команды. Это относится ко всем трем командам модификации. Хотя имеется большое количество ситуаций в которых будет полезно сделать запрос той таблицы которую вы хотите модифицировать причем во время ее модификации, это слишком усложняет операцию чтобы использовать ее на практике.</p>
<p>Не делайте ссылки к текущей строке таблицы указанной в команде, которая является соотнесенным подзапросом.</p>
<h3 id="использование-подзапросов-с-insert">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С INSERT</h3>
<p>INSERT - это самый простой случай. Вы уже видели как вставлять результаты запроса в таблицу. Вы можете использовать подзапросы внутри любого запроса, который генерирует значения для команды INSERT тем же самым способом, которым вы делали это для других запросов - т.е. внутри предиката или предложения HAVING.
Предположим, что мы имеем таблицу с именем SJpeople, столбцы которой совпадают со столбцами нашей таблицы Продавцов. Вы уже видели как заполнять таблицу подобно этой, заказчиками в городе, например, в San Jose:</p>
<pre><code>INSERT INTO SJpeople
SELECT *
FROM Salespeople
WHERE city='San Jose';
</code></pre>
<p>Теперь мы можем использовать подзапрос чтобы добавить к таблице SJpeople всех продавцов которые имеют заказчиков в San Jose, независимо от того, находятся ли там продавцы или нет:</p>
<pre><code>INSERT INTO SJpeople
SELECT *
FROM Salespeople
WHERE snum=ANY
( SELECT snum
FROM Customers
WHERE city=' (San (Jose' );
</code></pre>
<p>Оба запроса в этой команде функционируют также как если бы они не являлись частью выражения INSERT. Подзапрос находит все строки для заказчиков в San Jose и формирует набор значений snum. Внешний запрос выбирает строки из таблицы Salespeople, где эти значения snum найдены.
В этом примере, строки для продавцов Rifkin и Serres, которые назначены заказчикам в San Jose - Liu и Cisneros, будут вставлены в таблицу SJpeople.</p>
<h3 id="не-вставляйте-дубликаты-строк">НЕ ВСТАВЛЯЙТЕ ДУБЛИКАТЫ СТРОК</h3>
<p>Последовательность команд в предшествующем разделе может быть проблематичной. Продавец Serres находится в San Jose, и следовательно будет вставлен с помощью первой команды. Вторая команда попытается вставить его снова, поскольку он имеет еще одного заказчика в San Jose.
Если имеются любые ограничения в таблице SJpeople которые вынуждают ее значения быть уникальными, эта вторая вставка потерпит неудачу (как это и должно было быть). Двойные строки это плохо. (См. Главу 18 для подробностей об ограничениях. )
Было бы лучше если бы вы могли как-то выяснить, что эти значения уже были вставлены в таблицу, прежде чем вы попытаетесь сделать это снова, с помощью добавления другого подзапроса (использующего операторы типа EXISTS, IN, &lt; &gt; ALL, и так далее ) к предикату.
К сожалению, чтобы сделать эту работу, вы должны будете сослаться на саму таблицу SJpeople в предложении FROM этого нового подзапроса, а, как мы говорили ранее, вы не можете ссылаться на таблицу которая задействована (целиком ) в любом подзапросе команды модификации. В случае INSERT, это будет также препятствовать соотнесенным подзапросам, основанным на таблице в которую вы вставляете значения. Это имеет значение, потому что, с помощью INSERT, вы создаете новую строку в таблице. &quot;Текущая строка&quot; не будет существовать до тех пор, пока INSERT не закончит ее обрабатывать.</p>
<h3 id="использование-подзапросов-созданых-во-внешней-таблице-запроса">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ СОЗДАНЫХ ВО ВНЕШНЕЙ ТАБЛИЦЕ ЗАПРОСА</h3>
<p>Запрещение на ссылку к таблице которая модифицируется командой INSERT не предохранит вас от использования подзапросов которые ссылаются к таблице используемой в предложении FROM внешней команды SELECT. Таблица из которой вы выбираете значения, чтобы произвести их для INSERT, не будет задействована командой; и вы сможете ссылаться к этой таблице любым способом которыми вы обычно это делали, но только если эта таблица указана в автономном запросе. Предположим что мы имеем таблицу с именем Samecity в которой мы запомним продавцов с заказчиками в их городах.
Мы можем заполнить таблицу используя соотнесенный подзапрос:</p>
<pre><code>INSERT INTO (Samecity
SELECT *
FROM (Salespeople outer
WHERE city IN
( SELECT city
FROM Customers inner
WHERE inner.snum=outer.snum );
</code></pre>
<p>Ни таблица Samecity, ни таблица Продавцов не должны быть использованы во внешних или внутренних запросах INSERT. В качестве другого примера, предположим, что вы имеете премию для продавца который имеет самый большой порядок на каждый день. Вы следите за ним в таблице с именем Bonus, которая содержит поле snum продавцов, поле odate и поле amt. Вы должны заполнить эту таблицу информацией которая хранится в таблице Порядков, используя следующую команду:</p>
<pre><code>INSERT INTO Bonus
SELECT snum, odate, amt
FROM Orders a
WHERE amt=
( SELECT MAX (amt)
FROM Orders b
WHERE a.odate=b.odate );
</code></pre>
<p>Даже если эта команда имеет подзапрос который базируется на той же самой таблице что и внешний запрос, он не ссылается к таблице Bonus, на которую воздействует команда. Что для нас абсолютно приемлемо.
Логика запроса, естественно, должна просматривать таблицу Порядков, и находить для каждой строки максимум порядка сумм приобретений для этой даты. Если эта величина - такая же как у текущей строки, текущая строка является наибольшим порядком для этой даты, и данные вставляются в таблицу Bonus.</p>
<h3 id="использование-подзапросов-с-delete">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С DELETE</h3>
<p>Вы можете также использовать подзапросы в предикате команды DELETE.
Это даст вам возможность определять некоторые довольно сложные критерии чтобы установить, какие строки будут удаляться, что важно, так как вы конечно же не захотите по неосторожности удалить нужную строку.
Например, если мы закрыли наше ведомство в Лондоне, мы могли бы использовать следующий запрос чтобы удалить всех заказчиков назначенных к продавцам в Лондоне:</p>
<pre><code>DELETE
FROM Customers
WHERE snum=ANY
( SELECT snum
FROM Salespeople
WHERE city='London' );
</code></pre>
<p>Эта команда удалит из таблицы Заказчиков строки Hoffman и Clemens (назначенных для Peel), и Periera (назначенного к Motika).
Конечно, вы захотите удостовериться, правильно ли сформирована эта операция, прежде чем удалитт или изменитт строки Peel и Motika.
Это важно. Обычно, когда мы делаем модификацию в базе данных, котовая повлечет другие модификации, наше первое желание - сделать сначало основное действие, а затем проследить другие, вторичные. Этот пример, покажет, почему более эффективно делать наоборот, выполнив сначала вторичные действия.
Если, например, вы решили изменить значение поля city ваших продавцов везде, где они переназначены, вы должны рассмотреть всех этих заказчиков более сложным способом.
Так как реальные базы данных имеют тенденцию развиваться до значительно больших размеров чем наши небольшие типовые таблицы, это может стать серьезной проблемой. SQL может предоставить некоторую помощь в этой области используя механизм справочной целостности (обсужденной в Главе 19 ), но это не всегда доступно и не всегда применимо.
Хотя вы не можете ссылаться к таблице из которой вы будете удалять строки в предложении FROM подзапроса, вы можете в предикате, сослаться на текущую строку-кандидат этой таблицы - которая является строкой которая в настоящее время проверяется в основном предикате. Другими словами, вы можете использовать соотнесенные подзапросы. Они отличаются от тех соотнесенных подзапросов, которые вы могли использовать с INSERT, в котором они фактически базировались на строках-кандидатах таблицы задействованой в команде, а не на запросе другой таблицы.</p>
<pre><code>DELETE FROM Salespeople
WHERE EXISTS
( SELECT *
FROM Customers
WHERE rating=100
AND Salespeople.snum=Customers.snum );
</code></pre>
<p>Обратите внимание, что AND часть предиката внутреннего запроса ссылается к таблице Продавцов. Это означает что весь подзапрос будет выполняться отдельно для каждой строки таблицы Продавцов, также как это выполнялось с другими соотнесенными подзапросами. Эта команда удалит всех продавцов которые имели по меньшей мере одного заказчика с оценкой 100 в таблице Продавцов.
Конечно же, имеется другой способ сделать то же:</p>
<pre><code>DELETE FROM Salespeople
WHERE 100 IN
( SELECT rating
FROM Customers
WHERE Salespeople.snum=Customers.snum);
</code></pre>
<p>Эта команда находит все оценки для каждого заказчика продавцов и удаляет тех продавцов заказчики которого имеют оценку=100.
Обычно соотнесенные подзапросы - это подзапросы связанные с таблицей к которой они ссылаются во внешнем запросе (а не в самом предложении DELETE) - и также часто используемы. Вы можете найти наинизший порядок на каждый день и удалить продавцов которые произвели его, с помощью следующей команды:</p>
<pre><code>DELETE FROM Salespeople
WHERE (snum IN
( SELECT snum
FROM Orders
WHERE amt=
( SELECT MIN (amt)
FROM Orders b
WHERE a.odate=b.odate ));
</code></pre>
<p>Подзапрос в предикате DELETE, берет соотнесенный подзапрос. Этот внутренний запрос находит минимальный порядок суммы приобретеий для даты каждой строки внешнего запроса. Если эта сумма такая же как сумма текущей строки, предикат внешнего запроса верен, что означает, что текущая строка имеет наименьший порядок для этой даты. Поле snum продавца, ответственного за этот порядок, извлекается и передается в основной предикат команды DELETE, которая затем удаляет все строки с этим значением поля snum из таблицы Продавцов( так как snum - это первичный ключ таблицы Продавцов, то естественно там должна иметься только одна удаляемая строка для значения поля snum выведенного с помощью подзапроса. Если имеется больше одной строки, все они будут удалены. ) Поле snum=1007 которое будет удалено, имеет наименьшее значение на 3 Октября; поле snum =1002, наименьшее на 4 Октября; поле snum=1001, наименьшее в порядках на 5 Октября (эта команда кажется довольно резкой, особенно когда она удаляет Peel создавшего единственный порядок на 5 Октября, но зато это хорошая иллюстрация). Если вы хотите сохранить Peel, вы могли бы добавить другой подзапрос, который бы это делал:</p>
<pre><code>DELETE FROM Salespeople
WHERE (snum IN
( SELECT snum
FROM Orders a
WHERE amt=
( SELECT MIN (amt)
FROM Orders b
WHERE a.odate=b.odate )
AND 1 &lt;
( SELECT COUNT onum
FROM Orders b
WHERE a.odate=b.odate ));
</code></pre>
<p>Теперь для дня в котором был создан только один порядок, будет произведен счет=1 во втором соотнесенном подзапросе. Это сделает предикат внешнего запроса неправильным, и поля snum следовательно не будут переданы в основной предикат.</p>
<h3 id="использование-подзапросов-с-update">ИСПОЛЬЗОВАНИЕ ПОДЗАПРОСОВ С UPDATE</h3>
<p>UPDATE использует подзапросы тем же самым способом что и DELETE - внутри этого необязательного предиката. Вы можете использовать соотнесенные подзапросы или в форме пригодной для использования с DELETE - связаной или с модифицируемой таблицей или с таблицей вызываемой во внешнем запросе. Например, с помощью соотнесенного подзапроса к таблице которая будет модифицироваться, вы можете увеличить комиссионные всех продавцов которые были назначены по крайней мере двум заказчикам:</p>
<pre><code>UPDATE Salespeople
SET comm=comm + .01
WHERE 2 &lt;=
( SELECT COUNT (cnum)
FROM Customers
WHERE Customers.snum=
Salespeople.snum );
</code></pre>
<p>Теперь продавцы Peel и Serres, имеющие многочисленых заказчиков, получат повышение своих комиссионных.
Имеется разновидность последнего примера из предыдущего раздела с DELETE. Он уменьшает комиссионные продавцов которые произвели наименьшие порядки, но не стирает их в таблице:</p>
<pre><code>UPDATE Salespeople
SET comm=comm - .01
WHERE snum IN
( SELECT snum
FROM Orders a
WHERE amt=
( SELECT MIN (amt)
FROM Orders b
WHERE a.odate=b.odate ));
</code></pre>
<h3 id="столкновение-с-ограничениями-подзапросов-команды-dml">СТОЛКНОВЕНИЕ С ОГРАНИЧЕНИЯМИ ПОДЗАПРОСОВ КОМАНДЫ DML</h3>
<p>Неспособность сослаться к таблице задействованой в любом подзапросе из команды модификации (UPDATE), устраняет целые категории возможных действий. Например, вы не можете просто выполнить такую операцию как удаление всех заказчиков с оценками ниже средней. Вероятно лучше всего вы могли бы сначала (Шаг 1.), выполнить запрос, получающий среднюю величину, а затем (Шаг 2.), удалить все строки с оценкой ниже этой величины:</p>
<p>Шаг 1.</p>
<pre><code>SELECT AVG (rating)
FROM Customers;
</code></pre>
<p>Вывод=200.</p>
<p>Шаг 2.</p>
<pre><code>DELETE
FROM Customers
WHERE rating &lt; 200;
</code></pre>
<h3 id="резюме-10">РЕЗЮМЕ</h3>
<p>Теперь вы овладели тремя командами которые управляют всем содержанием вашей базы данных. Осталось только несколько общих вопросов относительно ввода и стирания значений таблицы, когда например эти команды могут выполниться данным пользователем в данной таблице и когда действия сделанные ими, становятся постоянными. Подведем итог: Вы используете команду INSERT чтобы добавлять строки в таблицу. Вы можете или дать имена значениям этих строк в предложении VALUES (когда только одна строка может быть добавлена ), или вывести значения с помощью запроса (когда любое число строк можно добавить одной командой). Если используется запрос, он не может ссылаться к таблице в которую вы делаете вставку,каким бы способом Вы ее ни делали, ни в предложении FROM, ни с помощью внешней ссылки (как это делается в соотнесенных подзапросах). Все это относится к любым подзапросам внутри этого запроса.
Запрос, однако, оставляет вам свободу использования соотнесенных подзапросов или подзапросов которые дают в предложении FROM имя таблице, которое уже было указано в предложении FROM внешнего запроса (это - общий случай для запросов).
DELETE и UPDATE используются чтобы, соответственно удалить строки из таблицы и изменить в них значения. Оба они применимы ко всем строкам таблицы, если не используется предикат определяющий какие строки должны быть удалены или модифицированы. Этот предикат может содержать подзапросы, которые могут быть связаны с таблицей, удаляемой, или модифицированой, с помощью внешней ссылки. Эти подзапросы, однако, не могут ссылать к таблице модифицируемой любым предложением FROM. Может показаться, что мы прошли материал SQL который обладает не самым понятным логическим порядком. Сначала мы сделали запрос таблицы которая уже заполнена данными. Потом мы показали как можно фактически помещать эти значения изначально. Но, как вы видете, полное ознакомление с запросами здесь неоценимо. Теперь, когда мы показали вам как заполнять значениями таблицы которые уже были созданы (по определению), мы покажем(со следующей главы) откуда появились эти таблицы.</p>
<h3 id="работа-с-sql-7">РАБОТА С SQL</h3>
<ul>
<li>Предположите, что имеется таблица называемая Multicust, с такими же именами столбцов что и таблица Продавцов. Напишите команду, которая бы вставила всех продавцов (из таблицы Продавцов)имеющих более чем одного заказчика в эту таблицу.</li>
<li>Напишите команду которая бы удаляла всех заказчиков не имеющих текущих порядков.</li>
<li>Напишите команду которая бы увеличила на двадцать процентов комиссионные всех продавцов имеющих общие текущие порядки выше чем $3,000.</li>
</ul>
<h2 id="глава-17-создание-таблиц">Глава 17. СОЗДАНИЕ ТАБЛИЦ</h2>
<p>ВПЛОТЬ ДО ЭТОГО МЕСТА, МЫ ЗАПРАШИВАЛИ ТАБЛИЦЫ данных и выполняли команды по извлечению этих данных, считая, что эти таблицы уже были созданы кем - то до нас . Это действительно наиболее реальная ситуация, когда небольшое колличество людей создают таблицы, которые затем используются другими людьми. Наша цель состоит в том, чтобы охватив информацию сначала более широко, перейти затем к более узким вопросам.</p>
<p>В этой главе, мы будем обсуждать создание, изменение, и удаление таблиц. Все это относится к самим таблицам, а не к данным которые в них содержатся. Будете или не будете Вы выполнять эти операции самостоятельно, но их концептуальное понимание увеличит ваше понимание языка SQL и природу таблиц которые вы используете. Эта глава вводит нас в область SQL называемую - DDL(Язык Определения Данных), где создаются объекты данных SQL.
Эта глава также покажет другой вид объекта данных SQL - Индекс. Индексы используются чтобы делать поиск более эффективным и, иногда, заставлять значения отличаться друга от друга. Они обычно работают незаметно для Вас, но если вы попробуете поместить значения в таблицу и они будут отклонены, из-за их неуникальности, это будет означать что другая строка имеет то же самое значение для этого поля, и что это поле имеет уникальный индекс или ограничение которое предписывает ему уникальность. Обсуждение вышеупомянутого, продолжится в Главе 18.</p>
<h3 id="команда-создания-таблицы">КОМАНДА СОЗДАНИЯ ТАБЛИЦЫ</h3>
<p>Таблицы создаются командой CREATE TABLE. Эта команда создает пустую таблицу - таблицу без строк. Значения вводятся с помощью DML команды INSERT (См. Главу 15). Команда CREATE TABLE в основном определяет имя таблицы, в виде описания набора имен столбцов указанных в определенном порядке. Она также определяет типы данных и размеры столбцов. Каждая таблица должна иметь по крайней мере один столбец.
Синтаксис команды CREATE TABLE:</p>
<pre><code>CREATE TABLE &lt;table-name &gt;
( &lt;column name &gt; &lt;data type&gt;[(&lt;size&gt;)],
&lt;column name &gt; &lt;data type&gt; [(&lt;size&gt;)] ... );
</code></pre>
<p>Как сказано в Главе 2, типы данных значительно меняются от программы к программе. Для совместимости со стандартом, они должны все, по крайней мере, поддерживать стандарт типа ANSI. Он описан в Приложении B. Так как пробелы используются для разделения частей команды SQL, они не могут быть частью имени таблицы (или любого другого объекта, такого как индекс). Подчеркивание (_ ) - обычно используется для разделения слов в именах таблиц.
Значение аргумента размера зависит от типа данных. Если вы его не указываете, ваша система сама будет назначать значение автоматически.
Для числовых значений, это - лучший выход, потому что в этом случае, все ваши поля такого типа получат один и тот же размер что освобождает вас от проблем их общей совместимости(см. Главу 14). Кроме того, использование аргумента размера с некоторыми числовым наборами, не совсем простой вопрос. Если вам нужно хранить большие числа, вам несомненно понадобятся гарантии, что поля достаточно велики чтобы вместить их.
Один тип данных для которого вы, в основном, должны назначать размер - CHAR. Аргумент размера - это целое число которое определяет максимальное число символов которое может вместить поле. Фактически, число символов поля может быть от нуля (если поле - NULL ) до этого числа.
По умолчанию, аргумент размера=1, что означает что поле может содержать только одну букву. Это конечно не совсем то что вы хотите.
Таблицы принадлежат пользователю который их создал, и имена всех таблиц принадлежащих данному пользователю должны отличаться друга от друга, как и имена всех столбцов внутри данной таблицы. Отдельные таблицы могут использовать одинаковые имена столбцов, даже если они принадлежат одному и тому же пользователю. Примером этому - столбец city в таблице Заказчиков и в таблице Продавцов. Пользователи не являющиеся владельцами таблиц могут ссылаться к этим таблицам с помощью имени владельца этих таблиц сопровождаемого точкой; например, таблица Employees созданая Smith будет называться Smith.Employees когда она упоминается каким-то другим пользователем (мы понимаем что Smith - это Идентификатор Разрешения (ID). (ID) сообщаемый пользователем (ваш разрешенный ID - это ваше имя в SQL. Этот вывод обсуждался в Главе 2, и будет продолжен в Главе 22 ).</p>
<p>Эта команда будет создавать таблицу Продавцов:</p>
<pre><code>CREATE TABLE Saleepeople
( snum integer,
sname char (10),
city char (10),
comm declmal );
</code></pre>
<p>Порядок столбцов в таблице определяется порядком в котором они указаны. Имя столбца не должно разделяться при переносе строки (что сделано для удобочитаемости ), но отделяется запятыми.</p>
<h3 id="индексы">ИНДЕКСЫ</h3>
<p>Индекс - это упорядоченный (буквенный или числовой ) список столбцов или групп столбцов в таблице. Таблицы могут иметь большое колличество строк, а, так как строки не находятся в каком-нибудь определенном порядке, на их поиск по указанному значению может потребовать время.
Индексный адрес - это и забота, и в то же время обеспечение способа объединения всех значений в группы из одной или больше строк, которые отличаются одна от другой. В Главе 18, мы будем описывать более непосредственный способ который заставит ваши значения быть уникальными. Но этот метод не существует в ранних версиях SQL. Так как уникальность часто необходима, индексы и использовались с этой целью.
Индексы - это средство SQL, которое родил сам рынок, а не ANSI. Поэтому, сам по себе стандарт ANSI в настоящее время не поддерживает индексы, хотя они очень полезны и широко применяемы.
Когда вы создаете индекс в поле, ваша база данных запоминает соответствующий порядок всех значений этого поля в области памяти. Предположим что наша таблица Заказчиков имеет тысячи входов, а вы хотите найти заказчика с номером=2999. Так как строки не упорядочены, ваша программа будет просматривать всю таблицу, строку за строкой, проверяя каждый раз значение поля cnum на равенство значению 2999. Однако, если бы имелся индекс в поле cnum, то программа могла бы выйти на номер 2999 прямо по индексу и дать информацию о том как найти правильную строку таблицы.
В то время как индекс значительно улучшает эффективность запросов, использование индекса несколько замедляет операции модификации DML(такие как INSERT и DELETE ), а сам индекс занимает объем памяти. Следовательно, каждый раз когда вы создаете таблицу Вы должны принять решение, индексировать ее или нет. Индексы могут состоять из многочисленых полей. Если больше чем одно поле указыватся для одного индекса, второе упорядочивается внутри первого, третье внутри второго, и так далее. Если вы имели первое и последнее имя в двух различных полях таблицы, вы могли бы создать индекс который бы упорядочил предыдущее поле внутри последующего. Это может быть выполнено независимо от способа упорядочивания столбцов в таблице.
Синтаксис для создания индекса - обычно следующий (помните, что это не ANSI стандарт ):</p>
<pre><code>CREATE INDEX &lt;index name&gt; ON &lt;table name&gt;
(&lt;column name&gt; [,&lt;column name&gt;]...);
</code></pre>
<p>Таблица, конечно, должна уже быть создана и должна содержать имя столбца. Имя индекса не может быть использовано для чего-то другого в базе данных (любым пользователем). Однажды созданый, индекс будет невидим пользователю. SQL сам решает когда он необходим чтобы ссылаться на него и делает это автоматически. Если, например, таблица Заказ чиков будет наиболее часто упоминаемой в запросах продавцов к их собственной клиентуре, было бы правильно создать такой индекс в поле snum таблицы Заказчиков.</p>
<pre><code>CREATE INDEX Clientgroup ON Customers (snum);
</code></pre>
<p>Теперь, тот продавец который имеет отношение к этой таблицы сможет найти собственную клиентуру очень быстро.</p>
<h3 id="уникальность-индекса">УНИКАЛЬНОСТЬ ИНДЕКСА</h3>
<p>Индексу в предыдущем примере, к счастью, не предписывается уникальность, несмотря на наше замечание, что это является одним из назначений индекса. Данный продавец может иметь любое число заказчиков. Однако, этого не случится если мы используем ключевое слово UNIQUE перед ключевым словом INDEX. Поле сnum, в качестве первичного ключа, станет первым кандидатом для уникального индекса:</p>
<pre><code>CREATE UNIQUE INDEX Custid ON Customers (cnum);
</code></pre>
<blockquote>
<p>ПРИМЕЧАНИЕ: эта команда будет отклонена если уже имеются идентичные значения в поле cnum. Лучший способ иметь дело с индексами состоит в том, чтобы создавать их сразу после того, как таблица создана и прежде, чем введены любые значения. Так же обратите внимание что, для уникального индекса более чем одного поля, это - комбинация значений, каждое из которых, может и не быть уникальным.</p>
</blockquote>
<p>Предыдущий пример - косвенный способ заставить поле cnum работать как первичный ключ таблицы Заказчиков. Базы данных воздействуют на первичные и другие ключи более непосредственно. Мы будем обсуждать этот вывод далее в Главах 18 и 19.</p>
<h3 id="удаление-индексов">УДАЛЕНИЕ ИНДЕКСОВ</h3>
<p>Главным признаком индекса является его имя - поэтому он может быть удален. Обычно пользователи не знают о существовании индекса. SQL автоматически определяет позволено ли пользователю использовать индекс, и если да, то разрешает использовать его. Однако, если вы хотите удалить индекс, вы должны знать его имя. Этот синтаксис используется для удаления индекса:</p>
<pre><code>DROP INDEX &lt;Index name&gt;;
</code></pre>
<p>Удаление индекса не воздействует на содержание полей.
ИЗМЕНЕНИЕ ТАБЛИЦЫ ПОСЛЕ ТОГО, КАК ОНА БЫЛА СОЗДАНА
Команда ALTER TABLE не часть стандарта ANSI; но это - широко доступная, и довольно содержательная форма, хотя ее возможности несколько ограничены. Она используется чтобы изменить определение существующей таблицы. Обычно, она добавляет столбцы к таблице. Иногда она может удалять столбцы или изменять их размеры, а также в некоторых программах добавлять или удалять ограничения (обсужденные в Главе 18). Типичный синтаксис чтобы добавить столбец к таблице :</p>
<pre><code>ALTER TABLE &lt;table name&gt; ADD &lt;column name&gt;
&lt;data type&gt; &lt;size&gt;;
</code></pre>
<p>Столбец будет добавлен со значением NULL для всех строк таблицы. Новый столбец станет последним по порядку столбцом таблицы. Вообще то, можно добавить сразу несколько новых столбцов, отделив их запятыми, в однй команде. Имеется возможность удалять или изменять столбцы. Наиболее часто, изменением столбца может быть просто увеличение его размера, или добавление( удаление ) ограничения. Ваша система должна убедиться, что любые изменения не противоречат существующим данным - например при попытке добавить ограничение к столбцу который уже имел значение при нарушении которого ограничение будет отклонено. Лучше всего дважды проверить это. По крайней мере, посмотрите документацию вашей системы чтобы убедиться, гарантирует ли она что именно это было причиной. Из-за нестандартного характера команды ALTER TABLE, вам все равно необходимо посмотреть тот раздел вашей системной документации где говорится об особых случаях.
ALTER TABLE - не действует, когда таблица должна быть переопределена, но вы должны разрабатывать вашу базу данных по возможности так чтобы не слишком ей в этом передоверяться. Изменение структуры таблицы когда она уже в использовании - опасно! Просмотрите внимательно таблицы, которые являясь вторичными таблицами с извлечеными данными из другой таблицы (смотри Главу 20 ), не долго правильно работают, а программы использующие вложенный SQL( Глава 25 ) выполняются неправильно или не всегда проавильно. Кроме того, изменение может стереть всех пользователей имеющих разрешение обращаться к таблице. По этим причинам, вы должны разрабатывать ваши таблицы так, чтобы использовать ALTER TABLE только в крайнем случае.
Если ваша система не поддерживает ALTER TABLE, или если вы хотите избежать ее использования, вы можете просто создать новую таблицу, с необходимыми изменениями при создании, и использовать команду INSERT с SELECT * запросом чтобы переписать в нее данные из старой таблицы.
Пользователям которым был предоставлен доступ к старой таблице (см. Главу 22 ) должен быть предоставлен доступ к новой таблице.</p>
<h3 id="удаление-таблиц">УДАЛЕНИЕ ТАБЛИЦ</h3>
<p>Вы должны быть собственником( т.е. быть создателем ) таблицы чтобы иметь возможность удалить ее. Поэтому не волнуйтесь о случайном разрушении ваших данных, SQL сначала потребует чтобы вы очистили таблицу прежде, чем удалит ее из базы данных. Таблица с находящимися в ней строками, не может быть удалена. Обратитесь к Главе 15 за подробностями относительно того как удалять строки из таблицы. Синтаксис для удаления вашей таблицы, если конечно она является пустой, следующая:</p>
<pre><code>DROP TABLE &lt; table name &gt;;
</code></pre>
<p>При подаче этой команды, имя таблицы больше не распознается и нет такой команды которая могла быть дана этому объекту. Вы должны убедиться, что эта таблица не ссылается внешним ключом к другой таблице(Внешние ключи обсуждаются в Главе 19 ), и что она не используется в определении Представления( Глава 20 ).
Эта команда фактически не является частью стандарта ANSI, но она обще поддерживаема и полезна. К счастью, она более проста, и следовательно более непротиворечива, чем ALTER TABLE . ANSI просто не имеет способа для определения разрушеных или неправильных таблиц.</p>
<h3 id="резюме-11">РЕЗЮМЕ</h3>
<p>Теперь Вы уже бегло ориентируетесь в основах определений данных. Вы можете создавать, изменять, и удалять таблицы. В то время как только первая из этих функций - часть официального стандарта SQL, другие будут время от времени меняться, особенно - ALTER TABLE. DROP TABLE позволяет вам избавиться от таблиц которые бесполезны. Она уничтожает только пустые таблицы, и следовательно не разрушает данные.
Вы теперь знаете об индексах а также, как их создавать и удалять.
SQL не дает вам большого управления над ими, так как реализация которую вы используете довольно удачно определяет, как быстро выполняются различные команды. Индексы - это один из инструментов дающий Вам возможность воздействовать непосредственно на эффективность ваших команд в SQL. Мы рассмотрели индексы здесь чтобы отличать их от ограничений, с которыми их нельзя путать. Ограничения - это тема Главы 18 и Главы 19.</p>
<h3 id="работа-с-sql-8">РАБОТА С SQL</h3>
<ul>
<li>Напишите предложение CREATE TABLE которое бы вывело нашу таблицу Заказчиков.</li>
<li>Напишите команду которая бы давала возможность пользователю быстро извлекать порядки сгруппированные по датам из таблицы Порядков.</li>
<li>Если таблица Порядков уже создана, как Вы можете заставить поле onum быть уникальным (если допустить что все текущие значения уникальны)?</li>
<li>Создайте индекс который бы разрешал каждому продавцу быстро отыскивать его порядки сгруппированные по датам.</li>
<li>Предположим, что каждый продавец имеет только одного заказчика с данной оценкой, введите команду которая его извлечет.</li>
</ul>
<h2 id="глава-18ограничение-значений-ваших-данных">Глава 18.ОГРАНИЧЕНИЕ ЗНАЧЕНИЙ ВАШИХ ДАННЫХ</h2>
<p>В ГЛАВЕ 17, ВЫ УЗНАЛИ КАК СОЗДАЮТСЯ ТАБЛИЦЫ. Теперь более тщательно с этого места мы покажем вам как вы можете устанавливать ограничения в таблицах. Ограничения - это часть определений таблицы, которое ограничивает значения которые вы можете вводить в столбцы. До этого места в книге, единственым ограничением на значения которые вы могли вводить, были тип данных и размер вводимых значений которые должны быть совместимы с теми столбцами в которые эти значения помещаются (как и определено в команде CREATE TABLE или команде ALTER TABLE). Ограничения дают вам значительно большие возможности и скоро вы это увидете. Вы также узнаете как определять значения по умолчанию в этой главе. По умолчанию - это значение которое вставляется автоматически в любой столбец таблицы, когда значение для этого столбца отсутствует в команде INSERT для этой таблицы. NULL - это наиболее широко используемое значение по умолчанию, но в этой главе будет показано как определять и другие значения по умолчанию.</p>
<h3 id="ограничение-таблиц">ОГРАНИЧЕНИЕ ТАБЛИЦ</h3>
<p>Когда вы создаете таблицу (или, когда вы ее изменяете ), вы можете помещать ограничение на значения которые могут быть введены в поля.
Если вы это сделали, SQL будет отклонять любые значения которые нарушают критерии которые вы определили. Имеется два основных типа ограничений - ограничение столбца и ограничение таблицы. Различие между ними в том, что ограничение столбца применяется только к индивидуальным столбцам, в то время как ограничение таблицы применяется к группам из одного и более столбцов.</p>
<h3 id="объявление-ограничений">ОБЪЯВЛЕНИЕ ОГРАНИЧЕНИЙ</h3>
<p>Вы вставляете ограничение столбца в конец имени столбца после типа данных и перед запятой. Ограничение таблицы помещаются в конец имени таблицы после последнего имени столбца, но перед заключительной круглой скобкой. Далее показан синтаксис для команды CREATE TABLE, расширенной для включения в нее ограничения:</p>
<pre><code>CREATE TABLE &lt; table name &gt;
(&lt; column name &gt; &lt;data type &gt; &lt; column constraint &gt;,
&lt; column name &gt; &lt; data type &gt; &lt; column constraint &gt; ...
&lt; table constraint &gt; (&lt; column name &gt;
[, &lt; column name &gt; ])... );
</code></pre>
<p>( Для краткости, мы опустили аргумент размера, который иногда используется с типом данных. ) Поля данные в круглых скобках после ограничения таблицы - это поля к которым применено это ограничение. Ограничение столбца, естественно, применяется к столбцам, после чьих имен оно следует. Остальная часть этой глава будет описывать различные типы ограничений и их использование.
ИСПОЛЬЗОВАНИЕ ОГРАНИЧЕНИЙ ДЛЯ ИСКЛЮЧЕНИЯ ПУСТЫХ( NULL ) УКАЗАТЕЛЕЙ
Вы можете использовать команду CREATE TABLE чтобы предохранить поле от разрешения в нем пустых(NULL) указателей с помощью ограничения NOT NULL. Это ограничение накладывается только для разнообразных столбцов.
Вы можете вспомнить что NULL - это специальное обозначение которое отмечает поле как пустое. NULL может быть полезен, когда имеются случаи, когда вы хотите быть от них гарантированы. Очевидно, что первичные ключи никогда не должны быть пустыми, поскольку это будет подрывать их функциональные возможности. Кроме того, такие поля как имена, требуют в большинстве случаев, определенных значений. Например, вы вероятно захотите иметь имя для каждого заказчика в таблице Заказчиков.
Если вы поместите ключевые слова NOT NULL сразу после типа данных (включая размер ) столбца, любая попытка поместить значение NULL в это поле будет отклонена. В противном случае, SQL понимает, что NULL разрешен.
Например, давайте улучшим наше определение таблицы Продавцов, не позволяя помещать NULL значения в столбцы snum или sname :</p>
<pre><code>CREATE TABLE Salespeople
( Snum integer NOT,
Sname char (10) NOT,
city char (10),
comm decimal);
</code></pre>
<p>Важно помнить, что любому столбцу с ограничением NOT NULL должно быть установлено значение в каждом предложении INSERT воздействующем на таблицу. При отсутствии NULL, SQL может не иметь значений для установки в эти столбцы, если конечно значение по умолчанию, описанное ранее в этой главе, уже не было назначено.
Если ваша система поддерживает использование ALTER TABLE чтобы добавлять новые столбцы к уже существующей таблице, вы можете вероятно помещать ограничение столбцов, типа NOT NULL, для этих новых столбцов.
Однако, если вы предписываете новому столбцу значение NOT NULL, теку-щая таблица должна быть пустой.</p>
<h3 id="убедитесь-что-значения---уникальны">УБЕДИТЕСЬ ЧТО ЗНАЧЕНИЯ - УНИКАЛЬНЫ</h3>
<p>В Главе 17, мы обсудили использование уникальных индексов чтобы заставить поля иметь различные значения для каждой строки. Эта практика - осталась с прежних времен, когда SQL поддерживал ограничение UNIQUE.
Уникальность - это свойство данных в таблице, и поэтому его более логично назвать как ограничение этих данных, а не просто как свойство логического отличия, связывающее объект данных (индекс ).
Несомненно, уникальные индексы - один из самых простых и наиболее эффективных методов предписания уникальности. По этой причине, некоторые реализации ограничения UNIQUE используют уникальные индексы; то-есть они создают индекс не сообщая вам об этом. Остается фактом, что вероятность беспорядка в базе данных достаточно мала, если вы предписываете уникальность вместе с ограничением.</p>
<h3 id="уникальность-как-ограничение-столбца">УНИКАЛЬНОСТЬ КАК ОГРАНИЧЕНИЕ СТОЛБЦА</h3>
<p>Время от времени, вы хотите убедиться, что все значения введеные в столбец отличаются друг от друга. Например, первичные ключи достаточно ясно это показывают. Если вы помещаете ограничение столбца UNIQUE в поле при создании таблицы, база данных отклонит любую попытку ввода в это поле для одной из строк, значения, которое уже представлено в другой строке. Это ограничение может применяться только к полям которые были обьявлены как непустые(NOT NULL), так как не имеет смысла позволить одной строке таблицы иметь значение NULL, а затем исключать другие строки с NULL значениями как дубликаты. Имеется дальнейшее усовершенствование нашей команды создания таблицы Продавцов :</p>
<pre><code>CREATE TABLE Salespeople
( Snum integer NOT NULL UNIQUE,
Sname char (10) NOT NULL UNIQUE,
city char (10),
comm decimal );
</code></pre>
<p>Когда вы обьявляете поле sname уникальным, убедитесь, что две Mary Smith будут введены различными способами - например, Mary Smith и M. Smith. В то же время это не так уж необходимо с функциональной точки зрения - потому что поле snum в качестве первичного ключа, все равно обеспечит отличие этих двух строк - что проще для людей использующих данные в таблицах, чем помнить что эти Smith не идентичны. Столбцы (не первичные ключи ) чьи значения требуют уникальности, называются ключами-кандидатами или уникальными ключами.</p>
<h3 id="уникальность-как-ограничение-таблицы">УНИКАЛЬНОСТЬ КАК ОГРАНИЧЕНИЕ ТАБЛИЦЫ</h3>
<p>Вы можете также определить группу полей как уникальную с помощью команды ограничения таблицы - UNIQUE. Объявление группы полей уникаль ной, отличается от объявления уникальными индивидуальных полей, так как это комбинация значений, а не просто индивидуальное значение, которое обязано быть уникальным. Уникальность группы - это представление порядка, так что бы пары строк со значениями столбцов &quot;a&quot;, &quot;b&quot; и &quot;b&quot;, &quot;a&quot; рассматривались отдельно одна от другой. Наша база данных сделана так чтобы каждый заказчик был назначен одному и только одному продавцу. Это означает что каждая комбинация номера заказчика(cnum) и номера продавца(snum) в таблице Заказчиков должна быть уникальной. Вы можете убедиться в этом, создав таблицу Заказчиков таким способом:</p>
<pre><code>CREATE TABLE Customers
( cnum integer NOT NULL,
cname char (10) NOT NULL,
city char (10),
rating integer,
snum integer NOT NULL,
UNIQUE (cnum, snum));
</code></pre>
<p>Обратите внимание что оба поля в ограничении таблицы UNIQUE все еще используют ограничение столбца - NOT NULL . Если бы мы использовали ограничение столбца UNIQUE для поля cnum, такое ограничение таблицы было бы необязательным. Если значения поля cnum различно для каждой строки, то не может быть двух строк с идентичной комбинацией значений полей cnum и snum. То же самое получится если мы обьявим поле snum уникальным, хотя это и не будет соответствовать нашему примеру, так как продавец будет назначен многочисленым заказчикам. Следовательно, ограничение таблицы - UNIQUE, наиболее полезно когда вы не хотите заставлять индивидуальные поля быть уникальными.
Предположим, например, что мы разработали таблицу чтобы следить за всеми порядками каждый день для каждого продавца. Каждая строка такой таблицы представляет сумму чисел любых порядков, а не просто индивидуальный порядок. В этом случае, мы могли бы устранить некоторые возможные ошибки убедившись что на каждый день имеется не более чем одна строка для данного продавца, или что каждая комбинация полей snum и odate является уникальной. Вот как например мы могли бы создать таблицу с именем Salestotal :</p>
<pre><code>CREATE TABLE Salestotal
( cnum integer NOT NULL,
odate date NULL,
totamt decimal,
UNIQUE (snum, odate));
</code></pre>
<p>Кроме того, имеется команда которую вы будете использовать чтобы помещать текущие данные в эту таблицу:</p>
<pre><code>INSERT INTO Salestotal
SELECT snum, odate, SUM (amt)
FROM Orders
GROUP BY snum, odate;
</code></pre>
<h3 id="ограничение-первичных-ключей">ОГРАНИЧЕНИЕ ПЕРВИЧНЫХ КЛЮЧЕЙ</h3>
<p>До этого мы воспринимали первичные ключи исключительно как логические понятия. Хоть мы и знаем что такое первичный ключ, и как он должен использоваться в любой таблице, мы не ведаем &quot;знает&quot; ли об этом SQL.
Поэтому мы использовали ограничение UNIQUE или уникальные индексы в первичных ключах чтобы предписывать им уникальность. В более ранних версиях языка SQL, это было необходимо, и могло выполняться этим способом. Однако теперь, SQL поддерживает первичные ключи непосредственно с ограничением Первичный Ключ (PRIMARE KEY). Это ограничение может быть доступным или недоступным вашей системе.
PRIMARY KEY может ограничивать таблицы или их столбцы. Это ограничение работает так же как и ограничение UNIQUE, за исключением когда только один первичный ключ (для любого числа столбцов ) может быть определен для данной таблицы. Имеется также различие между первичными ключами и уникальностью столбцов в способе их использоваться с внешними ключами, о которых будет рассказано в Главе 19. Синтаксис и определение их уникальности те же что и для ограничения UNIQUE.
Первичные ключи не могут позволять значений NULL. Это означает что, подобно полям в ограничении UNIQUE, любое поле используемое в ограничении PRIMARY KEY должно уже быть обьявлено NOT NULL. Имеется улучшеный вариант создания нашей таблицы Продавцов :</p>
<pre><code>CREATE TABLE Salestotal
( snum integer NOT NULL PRIMARY KEY,
sname char(10) NOT NULL UNIQUE,
city char(10),
comm decimal);
</code></pre>
<p>Как вы видете, уникальность (UNIQUE) полей может быть обьявлена для той же самой таблицы. Лучше всего помещать ограничение PRIMARY KEY в поле(или в поля) которое будет образовывать ваш уникальный идентификатор строки, и сохранить ограничение UNIQUE для полей которые должны быть уникальными логически (такие как номера телефона или поле sname ), а не для идентификации строк.</p>
<h3 id="первичные-ключи-более-чем-одного-поля">ПЕРВИЧНЫЕ КЛЮЧИ БОЛЕЕ ЧЕМ ОДНОГО ПОЛЯ</h3>
<p>Ограничение PRIMARY KEY может также быть применено для многочисленных полей, составляющих уникальную комбинацию значений. Предположим что ваш первичный ключ - это имя, и вы имеете первое имя и последнее имя сохраненными в двух различных полях (так что вы можете организовывать данные с помощью любого из них). Очевидно, что ни первое ни последнее имя нельзя заставить быть уникальным самостоятельно, но мы можем каждую из этих двух комбинаций сделать уникальной.
Мы можем применить ограничение таблицы PRIMARY KEY для пар:</p>
<pre><code>CREATE TABLE Namefield
( firstname char (10) NOT NULL,
lastname char (10) NOT NULL
city char (10),
PRIMARY KEY (firstname, lastname ));
</code></pre>
<p>Одна проблема в этом подходе та, что мы можем вынудить появление уникальности - например, введя Mary Smith и M. Smith. Это может ввести в заблуждение, потому что ваши служащие могут не знать кто из них кто.
Обычно более надежный способ чтобы определять числовое поле которое могло бы отличать одну строку от другой, это иметь первичный ключ, и применять ограничение UNIQUE для двух имен полей.</p>
<h3 id="проверка-значений-полей">ПРОВЕРКА ЗНАЧЕНИЙ ПОЛЕЙ</h3>
<p>Конечно, имеется любое число ограничений которые можно устанавливать для данных вводимых в ваши таблицы, чтобы видеть, например, находятся ли данные в соответствующем диапазоне или правильном формате, о чем SQL естественно не может знать заранее. По этой причине, SQL обеспечивает вас ограничением CHECK, которое позволяет вам установить условие которому должно удовлетворять значение вводимое в таблицу, прежде чем оно будет принято. Ограничение CHECK состоит из ключевого слова CHECK сопровождаемого предложением предиката, который использует указанное поле. Любая попытка модифицировать или вставить значение поля которое могло бы сделать этот предикат неверным - будет отклонена.
Давайте рассмотрим еще раз таблицу Продавцов. Столбец комиссионных выражается десятичным числом и поэтому может быть умножен непосредственно на сумму приобретений в результате чего будет получена сумма комиссионных(в долларах) продавца с установленым справа значком доллара( $ ) . Кто-то может использовать понятие процента, однако ведь, можно об этом и не знать. Если человек введет по ошибке 14 вместо .14 чтобы указать в процентах свои комиссионные, это будет расценено как 14.0, что является законным десятичным значением, и будет нормально воспринято системой. Чтобы предотвратить эту ошибку, мы можем наложить ограничение столбца - CHECK чтобы убедиться что вводимое значение меньше чем 1.</p>
<pre><code>CREATE TABLE Salespeople
( snum integer NOT NULL PRIMARY KEY,
sname char(10) NOT NULL UNIQUE,
city char(10),
comm decimal CHECK (comm &lt; 1 ));
</code></pre>
<h3 id="использование---check-чтобы-предопределять-допустимое-вводимое-значение">ИСПОЛЬЗОВАНИЕ - CHECK, ЧТОБЫ ПРЕДОПРЕДЕЛЯТЬ ДОПУСТИМОЕ ВВОДИМОЕ ЗНАЧЕНИЕ</h3>
<p>Мы можем также использовать ограничение CHECK чтобы защитить от ввода в поле определенных значений, и таким образом предотвратить ошибку.
Например, предположим, что единствеными городами в которых мы имели ведомства сбыта являются Лондон, Барселона, Сан Хосе, и Нью Йорк. Если вам известны все продавцы работающие в каждом из этих ведомств, нет необходимости позволять ввод других значений. Если же нет, использование ограничения может предотвратить опечатки и другие ошибки.</p>
<pre><code>CREATE TABLE Salespeople
(snum integer NOT NULL UNIQUE,
sname char(10) NOT NULL UNIQUE,
city char(10) CHECK,
(city IN ('London', 'New York', 'San Jose', 'Barselona')),
comm decimal CHECK (comm &lt; 1 ));
</code></pre>
<p>Конечно, если вы собираетесь сделать это, вы должны быть уверены что ваша компания не открыла уже новых других ведомств сбыта. Большинство программ баз данных поддерживают команду ALTER TABLE( см. Главу 17 ) которая позволяет вам изменять определение таблицы, даже когда она находится в использовании. Однако, изменение или удаление ограничений не всегда возможно для этих команд, даже там где это вроде бы поддерживается.
Если вы использовали систему которая не может удалять ограничения, вы будете должны создавать (CREATE) новую таблицу и передавать информацию из старой таблицы в нее всякий раз, когда вы хотите изменить ограничение. Конечно же Вы не захотите делать это часто, и со временем вообще перестанете это делать.</p>
<p>Создадим таблицу Порядков:</p>
<pre><code>CREATE TABLE Orders
(onum integer NOT NULL UNIQUE,
amt decimal,
odate date NOT NULL,
cnum integer NOT NULL,
snum integer NOT NULL);
</code></pre>
<p>Как мы уже говорили в Главе 2, тип DATЕ(ДАТА) широко поддерживается, но не является частью стандарта ANSI. Что же делать если мы используем базу данных, которая следуя ANSI, не распознает тип DATЕ? Если мы обьявим поле odate любым типом числа, мы не сможем использовать наклонную черту вправо (/) или черточку (-) в качестве разделителя. Так как печатаемые номера - это символы ASCII, мы можем обьявить тип поля odate - CHAR. Основная проблема в том, что мы будем должны использовать одиночные кавычки всякий раз, когда ссылаемся на значение поля odate в запросе. Нет более простого решения этой проблемы там где тип DATЕ стал таким популярным. В качестве иллюстрации, давайте обьявим поле odate - типом CHAR. Мы можем по крайней мере наложить на него наш формат с ограничением CHECK:</p>
<pre><code>CREATE TABLE Orders
( onum integer NOT NULL UNIQUE,
amt decimal,
odate char (10) NOT NULL CHECK (odate LIKE
'--/--/----'),
cnum NOT NULL,
snum NOT NULL );
</code></pre>
<p>Кроме того, если вы хотите, вы можете наложить ограничение, гарантирующие что введенные символы - числа, и что они - в пределах значений нашего диапазона.</p>
<h3 id="проверка-условий-базирующийся-на-многочисленых-полях">ПРОВЕРКА УСЛОВИЙ БАЗИРУЮЩИЙСЯ НА МНОГОЧИСЛЕНЫХ ПОЛЯХ</h3>
<p>Вы можете также использовать CHECK в качестве табличного ограничения. Это полезно в тех случаях когда вы хотите включить более одного поля строки в условие. Предположим что комиссионные .15 и выше, будут разрешены только для продавца из Барселоны. Вы можете указать это со следующим табличным ограничением CHECK :</p>
<pre><code>CREATE TABLE Salespeople
( snum integer NOT NULL UNIQUE,
sname char (10) NOT NULL UNIQUE,
city char(10),
comm decimal,
CHECK (comm &lt; .15 OR city='Barcelona'));
</code></pre>
<p>Как вы можете видеть, два различных поля должны быть проверены чтобы определить, верен предикат или нет. Имейте в виду, что это - два разных поля одной и той же строки. Хотя вы можете использовать многочисленые поля, SQL не может проверить более одной строки одновременно. Вы не можете например использовать ограничение CHECK чтобы удостовериться что все комиссионные в данном городе одинаковы. Чтобы сделать это, SQL должен всякий раз просматривая другие строки таблицы, когда вы модифицируете или вставляете строку, видеть, что значение комиссионных указано для текущего города. SQL этого делать не умеет.
Фактически, вы могли бы использовать сложное ограничение CHECK для вышеупомянутого, если бы знали заранее, каковы должны быть комиссионные в разных городах. Например, вы могли бы установить ограничение типа этого:</p>
<pre><code>CHECK (( comm=.15 AND clty='London' )
OR (comm=.14 AND city='Barcelona' )
OR (comm=11 AND city='San Jose').. )
</code></pre>
<p>Вы получили идею. Чем налагать такой комплекс ограничений, вы могли бы просто использовать представление с предложением WITH CHECK OPTION которое имеет все эти условия в своем предикате (смотри Главу 20 и 21 для информации о представлении и о WITH CHECK OPTION). Пользователи могут обращаться к представлению таблицы вместо самой таблицы. Одним из преимуществ этого будет то, что процедура изменения в ограничении не будет такой болезненной или трудоемкой. Представление с WITH CHECK OPTION - хороший заменитель ограничению CHECK, что будет показано в Главе 21.</p>
<h3 id="установка-значений-по-умолчанию">УСТАНОВКА ЗНАЧЕНИЙ ПО УМОЛЧАНИЮ</h3>
<p>Когда вы вставляете строку в таблицу без указания значений в ней для каждого поля, SQL должен иметь значение по умолчанию для включения его в определенное поле, или же команда будет отклонена. Наиболее общим значением по умолчанию является - NULL. Это - значение по умолчанию для любого столбца, которому не было дано ограничение NOT NULL или который имел другое назначение по умолчанию.
Значение DEFAULT(ПО УМОЛЧАНИЮ) указывается в команде CREATE TABLE тем же способом что и ограничение столбца, хотя, с технической точки зрения, значение DEFAULT не ограничительного свойства - оно не ограничивает значения которые вы можете вводить, а просто определяет, что может случиться если вы не введете любое из них. Предположим что вы работаете в оффисе Нью Йорка и подавляющее большинство ваших продавцов живут в Нью Йорке. Вы можете указать Нью Йорк в качестве значения поля city, по умолчанию, для вашей таблицы Продавцов:</p>
<pre><code>CREATE TABLE Salespeople
( snum integer NOT NULL UNIQUE,
sname char(10) NOT NULL UNIQUE,
city char(10) DEFAULT='New York',
comm decimal CHECK (comm &lt; 1);
</code></pre>
<p>Конечно, вводить значение Нью Йорк в таблицу каждый раз когда назначается новый продавец, не такая уж необходимость, и можно просто пренебречь им (не вводя его ) даже если оно должно иметь некоторое значение. Значение по умолчанию такого типа, более предпочтительно, чем, например, длинный конторский номер указывающий на ваше собственное ведомство, в таблице Порядков. Длинные числовые значения - более расположены к ошибке, поэтому если подавляющее большинство (или все ) ваших порядков должны иметь ваш собственный конторский номер, желательно устанавливать для них значение по умолчанию.
Другой способ использовать значение по умолчанию - это использовать его как альтернативу для NULL. Так как NULL (фактически) неверен при любом сравнении, ином чем IS NULL, он может быть исключен с помощью большинства предикатов. Иногда, вам нужно видеть пустые значения ваших полей не обрабатывая их каким-то определенным образом. Вы можете установить значение по умолчанию, типа нуль или пробел, которые функционально меньше по значению чем просто не установленное значение - пустое значение(NULL). Различие между ними и обычным NULL в том, что SQL будет обрабатывать их также как и любое другое значение.
Предположим, что заказчикам не назначены оценки изначально. Каждые шесть месяцев, вы повышаете оценку всем вашим заказчикам, имеющим оценку ниже средней, включая и тех кто предварительно не имел никакого назначения оценки. Если вы хотите выбрать всех этих заказчиков как группу, следующий запрос исключит всех заказчиков с оценкой=NULL:</p>
<pre><code>SELECT *
FROM Customers
WHERE rating &lt;=100;
</code></pre>
<p>Однако, если вы назначили значение поумолчанию=000, в поле rating, заказчики без оценок будут выбраны наряду с другими. Приоритет каждого метода - зависит от ситуации. Если вы будете делать запрос с помощью поля оценки, то захотите ли Вы включить строки без значений, или исключите их?
Другая характеристика значений по умолчанию этого типа, позволит обьявить Вам поле оценки - как NOT NULL. Если вы используете его поумолчанию, чтобы избежать значений =NULL, то это - вероятно хорошая защита от ошибок.
Вы можете также использовать ограничения UNIQUE или PRIMARY KEY в этом поле. Если вы сделаете это, то, имеете в виду, что только одна строка одновременно может иметь значение по умолчанию. Любую строку которая содержит значение по умолчанию нужно будет модифицировать прежде, чем другая строка с установкой по умолчанию будет вставлена.
Это не так как вы обычно используете значения по умолчанию, поэтому ограничения UNIQUE и PRIMARY KEY (особенно последнее ) обычно не устанавливаются для строк со значениями по умолчанию.</p>
<h3 id="резюме-12">РЕЗЮМЕ</h3>
<p>Вы теперь владеете несколькими способами управления значениями которые могут быть введены в ваши таблицы. Вы можете использовать ограничение NOT NULL чтобы исключать NULL, ограничение UNIQUE чтобы вынуждать все значения в группе из одного или более столбцов отличаться друг от друга, ограничение PRIMARY KEY, для того чтобы делать в основном то же самое что и UNIQUE но с различным окончанием, и наконец ограничение CHECK для определения ваших собственных сделанных на заказ условий, чтобы значения встреченные перед ними могли бы быть введены.
Кроме того, вы можете использовать предложение DEFAULT, которое будет автоматически вставлять значение по умолчанию в любое поле с именем не указаным в INSERT, так же как вставляется значение NULL когда предложение DEFAULT не установлено и отсутствует ограничение NOT NULL.
FOREIGN KEY или REFERENCES ограничения о которых вы узнаете в Главе 19 очень похожи на них, за исключением того, что они связывают группу из одного или более полей с другой группой, и таким образом сразу воздействуют на значения которые могут быть введены в любую из этих групп.</p>
<h3 id="работа-с-sql-9">РАБОТА С SQL</h3>
<ul>
<li>Создайте таблицу Порядков так чтобы все значения поля onum, а также все комбинации полей cnum и snum отличались друг от друга, и так что бы значения NULL исключались из поля даты.</li>
<li>Создайте таблицу Продавцов так чтобы комиссионные, по умолчанию, составляли 10%, не разрешались значения NULL, чтобы поле snum являлось первичным ключом, и чтобы все имена были в алфавитном порядке между A и M включительно( учитывая, что все имена будут напечатаны в верхнем регистре ).</li>
<li>Создайте таблицу Порядков, будучи уверенными в том что поле onum больше чем поле cnum, а cnum больше чем snum. Запрещены значения NULL в любом из этих трех полей.</li>
</ul>
<h2 id="глава-19-поддержка-целостности-ваших-данных">Глава 19. ПОДДЕРЖКА ЦЕЛОСТНОСТИ ВАШИХ ДАННЫХ</h2>
<p>РАНЕЕ В ЭТОЙ КНИГЕ, МЫ УКАЗЫВАЛИ НА ОПРЕДЕЛЕННЫЕ связи которые существуют между некоторыми полями наших типовых таблиц. Поле snum таблицы Заказчиков, например, соответствует полю snum в таблице Продавцов и таблице Порядков. Поле cnum таблицы Заказчиков также соответствует полю cnum таблицы Порядков. Мы назвали этот тип связи - справочной целостностью; и в ходе обсуждения, вы видели как ее можно использовать.</p>
<p>В этой главе, вы будете исследовать справочную целостность более подробно и выясним все относительно ограничений которые вы можете использовать чтобы ее поддерживать. Вы также увидете, как предписывается это ограничение когда вы используете команды модификации DML. Поскольку справочная целостность включает в себя связь полей или групп полей, часто в разных таблицах, это действие может быть несколько сложнее чем другие ограничения. По этой причине, хорошо иметь с ней полное знакомство, даже если вы не планируете создавать таблицы. Ваши команды модификации могут стать эффективнее с помощью ограничения справочной целостности (как и с помощью других ограничений, но ограничение справочной целостности может воздействовать на другие таблицы кроме тех в которых оно определено), а определенные функции запроса, такие как обьединения, являются многократно структурированы в терминах связей справочной целостности (как подчеркивалось в Главе 8 ).</p>
<h3 id="внешний-ключ-и-родительский-ключ">ВНЕШНИЙ КЛЮЧ И РОДИТЕЛЬСКИЙ КЛЮЧ</h3>
<p>Когда все значения в одном поле таблицы представлены в поле другой таблицы, мы говорим что первое поле ссылается на второе. Это указывает на прямую связь между значениями двух полей. Например, каждый из заказчиков в таблице Заказчиков имеет поле snum которое указывает на продавца назначенного в таблице Продавцов. Для каждого порядка в таблице Порядков, имеется один и только этот продавец и один и только этот заказчик. Это отображается с помощью полей snum и cnum в таблице Порядков.
Когда одно поле в таблице ссылается на другое, оно называется - внешним ключом; а поле на которое оно ссылается, называется - родительским ключом. Так что поле snum таблицы Заказчиков - это внешний ключ, а поле snum на которое оно ссылается в таблице Продавцов - это родительский ключ.
Аналогично, поля cnum и snum таблицы Порядков - это внешние ключи которые ссылаются к их родительским ключам с именами в таблице Заказчиков и таблице Продавцов. Имена внешнего ключа и родительского ключа не обязательно должны быть одинаковыми, это - только соглашение которому мы следуем чтобы делать соединение более понятным.</p>
<h3 id="много-столбцовые-внешние-ключи">МНОГО-СТОЛБЦОВЫЕ ВНЕШНИЕ КЛЮЧИ</h3>
<p>В действительности, внешний ключ не обязательно состоит только из одного поля. Подобно первичному ключу, внешний ключ может иметь любое число полей, которые все обрабатываются как единый модуль. Внешний ключ и родительский ключ на который он ссылается, конечно же, должны иметь одинаковый номер и тип поля, и находиться в одинаковом порядке.
Внешние ключи состоящие из одного поля - те что мы использовали исключительно в наших типовых таблицах, наиболее общие. Чтобы сохранить простоту нашего обсуждения, мы будем часто говорить о внешнем ключе как об одиночном столбце. Это не случайно. Если это не отметить, любой скажет о поле которое является внешним ключом, что оно также относится и к группе полей которая является внешним ключом.</p>
<h3 id="смысл-внешнего-и-родительского-ключей">СМЫСЛ ВНЕШНЕГО И РОДИТЕЛЬСКОГО КЛЮЧЕЙ</h3>
<p>Когда поле - является внешним ключом, оно определеным образом связано с таблицей на которую он ссылается. Вы, фактически, говорите - &quot;каждое значение в этом поле (внешнем ключе ) непосредственно привязано к значению в другом поле (родительском ключе ).&quot; Каждое значение (каждая строка ) внешнего ключа должно недвусмысленно ссылаться к одному и только этому значению (строке) родительского ключа. Если это так, то фактически ваша система, как говорится, будет в состоянии справочной целостности.
Вы можете увидеть это на примере. Внешний ключ snum в таблице Заказчиков имеет значение 1001 для строк Hoffman и Clemens. Предположим что мы имели две строки в таблице Продавцов со значением в поле snum=1001. Как мы узнаем, к которому из двух продавцов были назначены заказчики Hoffman и Clemens ? Аналогично, если нет никаких таких строк в таблице Продавцов, мы получим Hoffman и Clemens назначенными к продавцу которого не существует!</p>
<p>Понятно, что каждое значение во внешнем ключе должно быть представлено один, и только один раз, в родительском ключе.
Фактически, данное значение внешнего ключа может ссылаться только к одному значению родительского ключа не предполагая обратной возможности: т.е. любое число внешних ключей может ссылать к единственному значению родительского ключа. Вы можете увидеть это в типовых таблицах наших примеров. И Hoffman и Clemens назначены к Peel, так что оба их значения внешнего ключа совпадают с одним и тем же родительским ключом, что очень хорошо. Значение внешнего ключа должно ссылаться только к одному значению родительского ключа, зато значение родительского ключа может ссылаться с помощью любого колличества значений внешнего ключа. В качестве иллюстрации, значения внешнего ключа из таблицы Заказчиков, совпавшие с их родительским ключом в Продавцов таблице, показываются на Рисунке 19.1. Для удобства мы не учитывали поля не относящиеся к этому примеру.</p>
<h3 id="ограничение-foreign-key">ОГРАНИЧЕНИЕ FOREIGN KEY</h3>
<p>SQL поддерживает справочную целостность с ограничением FOREIGN KEY.
Хотя ограничение FOREIGN KEY - это новая особенность в SQL, оно еще не обеспечивает его универсальности. Кроме того, некоторые его реализации, более сложны чем другие. Эта функция должна ограничивать значения которые вы можете ввести в вашу базу данных чтобы заставить внешний ключ и родительский ключ соответствовать принципу справочной целостности. Одно из действий ограничения Внешнего Ключа - это отбрасывание значений для полей ограниченных как внешний ключ который еще не представлен в родительском ключе. Это ограничение также воздействует на вашу способность изменять или удалять значения родительского ключа (мы будем обсуждать это позже в этой главе ).</p>
<h3 id="как-можно-поля-представить-в-качестве-внешних-ключей">КАК МОЖНО ПОЛЯ ПРЕДСТАВИТЬ В КАЧЕСТВЕ ВНЕШНИХ КЛЮЧЕЙ</h3>
<p>Вы используете ограничение FOREIGN KEY в команде CREATE TABLE (или ALTER TABLE ), которая содержит поле которое вы хотите обьявить внешним ключом. Вы даете имя родительскому ключу на которое вы будете ссылаться внутри ограничения FOREIGN KEY. Помещение этого ограничения в команду - такое же что в для других ограничений обсужденных в предыдущей главе.</p>
<pre><code>{}
</code></pre>
<p>Рисунок 19.1: Внешний Ключ таблицы Заказчиков с родительским ключом
Подобно большинству ограничений, оно может быть ограничением таблицы или столбца, в форме таблицы позволяющей использовать многочисленые поля как один внешний ключ.</p>
<h3 id="внешний-ключ-как-ограничение-таблицы">ВНЕШНИЙ КЛЮЧ КАК ОГРАНИЧЕНИЕ ТАБЛИЦЫ</h3>
<p>Синтаксис ограничения таблицы FOREIGN KEY:</p>
<pre><code>FOREIGN KEY &lt;column list&gt; REFERENCES
&lt;pktable&gt; [ &lt;column list&gt; ]
</code></pre>
<p>Первый список столбцов - это список из одного или более столбцов таблицы, которые отделены запятыми и будут созданы или изменены этой командой. Pktable - это таблица содержащая родительский ключ. Она может быть таблицей, которая создается или изменяется текущей командой.
Второй список столбцов - это список столбцов которые будут составлять родительский ключ. Списки двух столбцов должны быть совместимы, т.е.:</p>
<ul>
<li>Они должны иметь одинаковое число столбцов.</li>
<li>В данной последовательности, первый, второй, третий, и т.д., столбцы списка столбцов внешнего ключа, должны иметь одинаковые типы данных и размеры, что и первый, второй, третий, и т.д., столбцы списка столбцов родительского ключа. Столбцы в списках обоих столбцов не должны иметь одинаковых имен, хотя мы и использовали такой способ в наших примерах чтобы делать связь более понятной.</li>
</ul>
<p>Создадим таблицу Заказчиков с полем snum определенным в качестве внешнего ключа ссылающегося на таблицу Продавцов:</p>
<pre><code>CREATE TABLE Customers
( cnum integer NOT NULL PRIMARY KEY
cname char(10),
city char(10),
snum integer,
FOREIGN KEY (snum) REFERENCES Salespeople
( snum );
</code></pre>
<p>Имейте в виду, что при использовании ALTER TABLE вместо CREATE TABLE, для применения ограничения FOREIGN KEY, значения которые Вы указываете во внешнем ключе и родительском ключе, должны быть в состоянии справочной целостности. Иначе команда будет отклонена. Хотя ALTER TABLE очень полезна из-за ее удобства, вы должны будете в вашей системе, по возможности каждый раз, сначала формировать структурные принципы, типа справочной целостности.</p>
<h3 id="внешний-ключ-как-ограничение-столбцов">ВНЕШНИЙ КЛЮЧ КАК ОГРАНИЧЕНИЕ СТОЛБЦОВ</h3>
<p>Вариант ограничения столбца ограничением FOREIGN KEY - по другому называется - ссылочное ограничение (REFERENCES), так как он фактически не содержит в себе слов FOREIGN KEY, а просто использует слово REFERENCES, и далее имя родительского ключа, подобно этому:</p>
<pre><code>CREATE TABLE Customers
( cnum integer NOT NULL PRIMARY KEY,
cname char(10),
city char(10),
snum integer REFERENCES Salespeople (snum));
</code></pre>
<p>Вышеупомянутое определяет Customers.snum как внешний ключ у которого родительский ключ - это Salespeople.snum. Это эквивалентно такому ограничению таблицы:</p>
<pre><code>FOREIGN KEY (snum) REGERENCES Salespeople (snum)
</code></pre>
<h3 id="не-указывать-список-столбцов-первичных-ключей">НЕ УКАЗЫВАТЬ СПИСОК СТОЛБЦОВ ПЕРВИЧНЫХ КЛЮЧЕЙ</h3>
<p>Используя ограничение FOREIGN KEY таблицы или столбца, вы можете не указывать список столбцов родительского ключа если родительский ключ имеет ограничение PRIMARY KEY. Естественно, в случае ключей со многими полями, порядок столбцов во внешних и первичных ключах должен совпадать, и, в любом случае, принцип совместимости между двумя ключами все еще применим. Например, если мы поместили ограничение PRIMARY KEY в поле snum таблицы Продавцов, мы могли бы использовать его как внешний ключ в таблице Заказчиков (подобно предыдущему примеру) в этой команде:</p>
<pre><code>CREATE TABLE Customers
( cnum integer NOT NULL PRIMARY KEY,
cname char(10),
city char(10),
snum integer REFERENCES Salespeople);
</code></pre>
<p>Это средство встраивалось в язык, чтобы поощрять вас использовать первичные ключи в качестве родительских ключей.</p>
<h3 id="как-справочная-целостность-ограничивает-значения-родительского-ключа">КАК СПРАВОЧНАЯ ЦЕЛОСТНОСТЬ ОГРАНИЧИВАЕТ ЗНАЧЕНИЯ РОДИТЕЛЬСКОГО КЛЮЧА</h3>
<p>Поддержание справочной целостности требует некоторых ограничений на значения, которые могут быть представлены в полях, обьявленных как внешний ключ и родительский ключ. Родительский ключ должен быть структурен, чтобы гарантировать, что каждое значение внешнего ключа будет соответствовать одной указанной строке. Это означает, что он (ключ) должен быть уникальным и не содержать никаких пустых значений(NULL).
Этого не достаточно для родительского ключа в случае выполнения такого требования как при объявлении внешнего ключа. SQL должен быть уверен что двойные значения или пустые значения (NULL) не были введены в родительский ключ. Следовательно вы должны убедиться, что все поля, которые используются как родительские ключи, имеют или ограничение PRIMARY KEY или ограничение UNIQUE, наподобии ограничения NOT NULL.</p>
<h3 id="первичный-ключ-как-уникальный-внешний-ключ">ПЕРВИЧНЫЙ КЛЮЧ КАК УНИКАЛЬНЫЙ ВНЕШНИЙ КЛЮЧ</h3>
<p>Ссылка ваших внешних ключей только на первичные ключи, как мы это делали в типовых таблицах, - хорошая стратегия. Когда вы используете внешние ключи, вы связываете их не просто с родительскими ключами на которые они ссылаются; вы связываете их с определенной строкой таблицы где этот родительский ключ будет найден. Сам по себе родительский ключ не обеспечивает никакой информации которая бы не была уже представлена во внешнем ключе. Смысл, например, поля snum как внешнего ключа в таблице Заказчиков - это связь которую он обеспечивает, не к значению поля snum на которое он ссылается, а к другой информации в таблице Продавцов, такой например как, имена продавцов, их местоположение, и так далее. Внешний ключ - это не просто связь между двумя идентичными значениями; это - связь, с помощью этих двух значений, между двумя строками таблицы указанной в запросе.
Это поле snum может использоваться чтобы связывать любую информацию в строке из таблицы Заказчиков со ссылочной строкой из таблицы Продавцов - например чтобы узнать - живут ли они в том же самом городе, кто имеет более длинное имя, имеет ли продавец кроме данного заказчика каких-то других заказчиков, и так далее.
Так как цель первичного ключа состоит в том, чтобы идентифицировать уникальность строки, это более логичный и менее неоднозначный выбор для внешнего ключа. Для любого внешнего ключа который использует уникальный ключ как родительский ключ, вы должны создать внешний ключ который бы использовал первичный ключ той же самой таблицы для того же самого действия. Внешний ключ который не имеет никакой другой цели кроме связывания строк, напоминает первичный ключ используемый исключительно для идентификации строк, и является хорошим средством сохранить структуру вашей базы данных ясной и простой, и - следовательно создающей меньше трудностей.</p>
<h3 id="ограничения-внешнего-ключа">ОГРАНИЧЕНИЯ ВНЕШНЕГО КЛЮЧА</h3>
<p>Внешний ключ, в частности, может содержать только те значения которые фактически представлены в родительском ключе или пустые(NULL). Попытка ввести другие значения в этот ключ будет отклонена.
Вы можете обьявить внешний ключ как NOT NULL, но это необязательно, и в большинстве случаев, нежелательно. Например, предположим, что вы вводите заказчика не зная заранее, к какому продавцу он будет назначен. Лучший выход в этой ситуации, будет если использовать значение NOT NULL, которое должно быть изменено позже на конкретное значение.</p>
<h3 id="что-случится-если-вы-выполните-команду-модификации">ЧТО СЛУЧИТСЯ, ЕСЛИ ВЫ ВЫПОЛНИТЕ КОМАНДУ МОДИФИКАЦИИ</h3>
<p>Давайте условимся, что все внешние ключи созданые в наших таблицах примеров, обьявлены и предписаны с ограничениями внешнего ключа, следующим образом:</p>
<pre><code>CREATE TABLE Salespeople
(snum integer NOT NULL PRIMARY KEY,
sname char(10) NOT NULL,
city char(10),
comm decimal);

CREATE TABLE Customers
(cnum integer NOT NULL PRIMARY KEY,
cname char(10) NOT NULL,
city char(10),
rating integer,
snum integer,
FOREIGN KEY (snum) REFERENCES Salespeople,
UNIQUE (cnum, snum) ;

CREATE TABLE Orders
(cnum integer NOT NULL PRIMARY KEY,
amt decimal,
odate date NOT NULL,
cnum integer NOT NULL
snum integer NOT NULL
FOREIGN KEY (cnum, snum) REFERENCES
CUSTOMERS (cnum, snum);
</code></pre>
<h3 id="включение-описаний-таблицы">ВКЛЮЧЕНИЕ ОПИСАНИЙ ТАБЛИЦЫ</h3>
<p>Имеется несколько атрибутов таких определений о которых нужно поговорить. Причина по которой мы решили сделать поля cnum и snum в таблице Порядков, единым внешним ключом - это гарантия того, что для каждого заказчика содержащегося в порядках, продавец кредитующий этот порядок - тот же что и указаный в таблице Заказчиков. Чтобы создать такой внешний ключ, мы были бы должны поместить ограничение таблицы UNIQUE в два поля таблицы Заказчиков, даже если оно необязательно для самой этой таблицы. Пока поле cnum в этой таблица имеет ограничение PRIMARY KEY, оно будет уникально в любом случае, и следовательно невозможно получить еще одну комбинацию поля cnum с каким-то другим полем.
Создание внешнего ключа таким способом поддерживает целостность базы данных, даже если при этом вам будет запрещено внутреннее прерывание по ошибке и кредитовать любого продавца, иного чем тот который назначен именно этому заказчику. С точки зрения поддержания целостности базы данных, внутренние прерывания (или исключения ) конечно же нежелательны. Если вы их допускаете и в то же время хотите поддерживать целостность вашей базы данных, вы можете обьявить поля snum и cnum в таблице Порядков независимыми внешними ключами этих полей в таблице Продавцов и таблице Заказчиков, соответственно. Фактически, использование поля snum в таблице Порядков, как мы это делали, необязательно, хотя это полезно было сделать для разнообразия. Поле cnum связывая каждый порядок заказчиков в таблице Заказчиков, в таблице Порядков и в таблице Заказчиков, должно всегда быть общим чтобы находить правильное поле snum для данного порядка (не разрешая никаких исключений).
Это означает что мы записываем фрагмент информации - какой заказчик назначен к какому продавцу - дважды, и нужно будет выполнять дополнительную работу чтобы удостовериться, что обе версии согласуются. Если мы не имеем ограничения внешнего ключа как сказано выше, эта ситуация будет особенно проблематична, потому что каждый порядок нужно будет проверять вручную (вместе с запросом ), чтобы удостовериться что именно соответствующий продавец кредитовал каждую соответствующую продажу.</p>
<p>Наличие такого типа информационной избыточности в вашей базе данных, называется деморализация (denormalization ), что не желательно в идеальной реляционной базе данных, хотя практически и может быть разрешена. Деморализация может заставить некоторые запросы выполняться быстрее, поскольку запрос в одной таблице выполняется всегда значительно быстрее чем в обьединении.</p>
<h3 id="действие-ограничений">ДЕЙСТВИЕ ОГРАНИЧЕНИЙ</h3>
<p>Как такие ограничения воздействуют на возможность и невозможность Вами использовать команды модификации DML? Для полей, определенных как внешние ключи, ответ довольно простой: любые значения которые вы помещаете в эти поля с командой INSERT или UPDATE должны уже быть представлены в их родительских кючах. Вы можете помещать пустые(NULL) значения в эти поля, несмотря на то что значения NULL не позволительны в родительских ключах, если они имеют ограничение NOT NULL. Вы можете удалять (DELETE ) любые строки с внешними ключами не используя родительские ключи вообще. Поскольку затронут вопрос об изменении значений родительского ключа, ответ, по определению ANSI, еще проще, но возможно несколько более ограничен: любое значение родительского ключа ссылаемого с помощью значения внешнего ключа, не может быть удалено или изменено. Это означает, например, что вы не можете удалить заказчика из таблицы Заказчиков пока он еще имеет порядки в таблице Порядков. В зависимости от того, как вы используете эти таблицы, это может быть или желательно или хлопотно. Однако - это конечно лучше чем иметь систему, которая позволит вам удалить заказчика с текущими порядками и оставить таблицу Порядков ссылающейся на несуществующих заказчиков.
Смысл этой системы оганичения в том, что создатель таблицы Порядков, используя таблицу Заказчиков и таблицу Продавцов как родительские ключи может наложить значительные ограничения на действия в этих таблицах. По этой причине, вы не сможете использовать таблицу которой вы не распоряжаетесь (т.е. не вы ее создавали и не вы являетесь ее владельцем), пока владелец(создатель) этой таблицы специально не передаст вам на это право (что объясняется в Главе 22).
Имеются некоторые другие возможные действия изменения родительского ключа, которые не являются частью ANSI, но могут быть найдены в некоторых коммерческих программах. Если вы хотите изменить или удалить текущее ссылочное значение родительского ключа, имеется по существу три возможности:</p>
<ul>
<li>Вы можете ограничить, или запретить, изменение (способом ANSI ), обозначив, что изменения в родительском ключе - ограничены.</li>
<li>Вы можете сделать изменение в родительском ключе и тем самым сделать изменения во внешнем ключе автоматическим, что называется - каскадным изменением.</li>
<li>Вы можете сделать изменение в родительском ключе, и установить внешний ключ в NULL, автоматически (полагая, что NULLS разрешен во внешнем ключе ), что называется - пустым изменением внешнего ключа.</li>
</ul>
<p>Даже в пределах этих трех категорий, вы можете не захотеть обрабатывать все команды модификации таким способом. INSERT, конечно, к делу не относится. Он помещает новые значения родительского ключа в таблицу, так что ни одно из этих значений не может быть вызвано в данный момент. Однако, вы можете захотеть позволить модификациям быть каскадными, но без удалений, и наоборот. Лучшей может быть ситуация которая позволит вам определять любую из трех категорий, независимо от команд UPDATE и DELETE. Мы будем следовательно ссылаться на эффект модификации (update effects) и эффект удаления (delete effects ), котторые определяют, что случитс если вы выполните команды UPDATE или DELETE в родительском ключе. Эти эффекты, о которых мы говорили, называются: Ограниченные (RESTRICTED) изменения, Каскадируемые (CASCADES) изменения, и Пустые (NULL) изменения.
Фактические возможности вашей системы должны быть в строгом стандарте ANSI - это эффекты модификации и удаления, оба, автоматически ограниченнные - для более идеальной ситуации описаной выше. В качестве иллюстрации, мы покажем несколько примеров того, что вы можете делать с полным набором эффектов модификации и удаления. Конечно, эффекты модификации и удаления, являющиеся нестандартными средствами, испытывают недостаток в стандартном госинтаксисе. Синтаксис который мы используем здесь, прост в написании и будет служить в дальнейшем для иллюстрации функций этих эффектов.
Для полноты эксперимента, позволим себе предположить что вы имеете причину изменить поле snum таблицы Продавцов в случае, когда наша таблица Продавцов изменяет разделы. (Обычно изменение первичных ключей это не то что мы рекомендуем делать практически. Просто это еще один из доводов для имеющихся первичных ключей которые не умеют делать ничего другого кроме как, действовать как первичные ключи: они не должны изменяться. ) Когда вы изменяете номер продавца, вы хотите чтобы были сохранены все его заказчики. Онако, если этот продавец покидает свою фирму или компанию, вы можете не захотеть удалить его заказчиков, при удалении его самого из базы данных. Взамен, вы захотите убедиться, что заказчики назначены кому-нибудь еще. Чтобы сделать это вы должны указать UPDATE с Каскадируемым эффектом, и DELETE с Ограниченным эффектом.</p>
<pre><code>CREATE TABLE Customers
(cnum integer NOT NULL PRIMARY KEY,
cname char(10) NOT NULL,
city char(10),
rating integer,
snum integer REFERENCES Salespeople,
UPDATE OF Salespeople CASCADES,
DELETE OF Salespeople RESTRICTED);
</code></pre>
<p>Если вы теперь попробуете удалить Peel из таблицы Продавцов, команда будет не допустима, пока вы не измените значение поля snum заказчиков Hoffman и Clemens для другого назначенного продавца. С другой стороны, вы можете изменить значение поля snum для Peel на 1009, и Hoffman и Clemens будут также автоматически изменены.
Третий эффект - Пустые (NULL) изменения. Бывает, что когда продавцы оставляют компанию, их текущие порядки не передаются другому продавцу.
С другой стороны, вы хотите отменить все порядки автоматически для заказчиков, чьи счета вы удалите. Изменив номера продавца или заказчика можно просто передать их ему. Пример ниже показывает, как вы можете создать таблицу Порядков с использованием этих эффектов.</p>
<pre><code>CREATE TABLE Orders
(onum integer NOT NULL PRIMARY KEY,
amt decimal,
odate date NOT NULL
cnum integer NOT NULL REFERENCES Customers
snum integer REFERENCES Salespeople,
UPDATE OF Customers CASCADES,
DELETE OF Customers CASCADES,
UPDATE OF Salespeople CASCADES,
DELETE OF Salespeople NULLS);
</code></pre>
<p>Конечно, в команде DELETE с эффектом Пустого изменения в таблице Продавцов, ограничение NOT NULL должно быть удалено из поля snum.</p>
<h3 id="внешние-ключи-которые-ссылаются-обратно-к-их-подчиненым-таблицам">ВНЕШНИЕ КЛЮЧИ КОТОРЫЕ ССЫЛАЮТСЯ ОБРАТНО К ИХ ПОДЧИНЕНЫМ ТАБЛИЦАМ</h3>
<p>Как было упомянуто ранее, ограничение FOREIGN KEY может представить имя этой частной таблице, как таблицы родительского ключа. Далеко не будучи простой, эта особенность может пригодиться. Предположим, что мы имеем таблицу Employees с полем manager(администратор). Это поле содержит номера каждого из служащих, некоторые из которых являются еще и администраторами. Но так как каждый администратор - в то же время остается служащим, то он естественно будут также представлен в этой таблице. Давайте создадим таблицу, где номер служащего (столбец с именем empno ), объявляется как первичный ключ, а администратор, как внешний ключ, будет ссылаться на нее:</p>
<pre><code>CREATE TABLE Employees
(empno integer NOT NULL PRIMARY KEY,
name char(10) NOT NULL UNIOUE,
manager integer REFERENCES Employees);
</code></pre>
<p>( Так как внешний ключ это ссылаемый первичный ключ таблицы, список столбцов может быть исключен. ) Имеется содержание этой таблицы:</p>
<table>
<thead>
<tr>
<th>   EMPNO</th>
<th>   NAME</th>
<th>   MANAGER</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Terrence<br style="margin: 0px; padding: 0px;"></td>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
<td>   Atali<br style="margin: 0px; padding: 0px;"></td>
<td>   NULL<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1688<br style="margin: 0px; padding: 0px;"></td>
<td>   McKenna<br style="margin: 0px; padding: 0px;"></td>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   2002<br style="margin: 0px; padding: 0px;"></td>
<td>   Collier<br style="margin: 0px; padding: 0px;"></td>
<td>   2007<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Как вы можете видеть, каждый из них( но не Atali ), ссылается на другого служащего в таблице как на своего администратора. Atali, имеющий наивысший номер в таблице, должен иметь значение установленное в NULL. Это дает другой принцип справочной целостности. Внешний ключ, который ссылается обратно к частной таблице, должен позволять значения=NULL. Если это не так, как бы вы могли вставить первую строку ? Даже если эта первая строка ссылается к себе самой, значение родительского ключа должно уже быть установлено, когда вводится значение внешнего ключа. Этот принцип будет верен, даже если внешний ключ ссылается обратно к частной таблице не напрямую а с помощью ссылки к другой таблице, которая затем ссылается обратно к таблице внешнего ключа. Например, предположим, что наша таблица Продавцов имеет дополнительное поле
которое ссылается на таблицу Заказчиков, так, что каждая таблица ссылается на другую, как показано в следующем операторе CREATE TABLE:</p>
<pre><code>CREATE TABLE Salespeople
(snum integer NOT NULL PRIMARY KEY,
sname char(10) NOT NULL,
city char(10),
comm declmal,
cnum integer REFERENCES Customers);

CREATE TABLE Customers
(cnum integer NOT NULL PRIMARY KEY,
cname char(10) NOT NULL,
city char(10),
rating integer,
snum integer REFERENCES Salespeople);
</code></pre>
<p>Это называется - перекрестной ссылкой. SQL поддерживает это теоретически, но практически это может составить проблему. Любая таблица из этих двух, созданная первой является ссылочной таблицей которая еще не существует для другой. В интересах обеспечения перекрестной ссылки, SQL фактически позволяет это, но никакая таблица не будет пригодна для использования пока они обе находятся в процессе создания. С другой стороны, если эти две таблицы создаются различными пользователями, проблема становится еще более трудной. Перекрестная ссылка может стать полезным инструментом, но она не без неоднозначности и опасностей.
Предшествующий пример, например, не совсем пригоден для использования: потому что он ограничивает продавца одиночным заказчиком, и кроме того совсем необязательно использовать перекресную ссылку чтобы достичь этого. Мы рекомендуем чтобы вы были осторожны в его использовании и анализировали, как ваши программы управляют эффектами модификации и удаления а также процессами привилегий и диалоговой обработки запросов перед тем как вы создаете перекресную систему справочной целостности.
( Привилегии и диалоговая обработка запросов будут обсуждаться, соответственно, в Главах 22 И 23.)</p>
<h3 id="резюме-13">РЕЗЮМЕ</h3>
<p>Теперь вы имеете достаточно хороше управление справочной целостностью. Основная идея в том, что все значения внешнего ключа ссылаются к указанной строке родительского ключа. Это означает, что каждое значение внешнего ключа должно быть представлено один раз, и только один раз, в родительском ключе. Всякий раз, когда значение помещается во внешний ключ, родительский ключ проверяется, чтобы удостовериться, что его значение представлено; иначе, команда будет отклонена. Родительский ключ должен иметь Первичный Ключ (PRIMARY KEY) или Уникальное (UNIQUE) ограничение, гарантирующее, что значение не будет представлено более чем один раз. Попытка изменить значение родительского ключа, которое в настоящее время представлено во внешнем ключе, будет вообще отклонена. Ваша система может, однако, предложить вам выбор, чтобы получить значение внешнего ключа установленого в NULL или для получения нового значения родителького ключа, и указания какой из них может быть получен независимо для команд UPDATE и DELETE. Этим завершается наше обсуждение команды CREATE TABLE. Далее мы представим вас другому типу команды - CREATE. В Главе 20, вы обучитесь представлению объектов данных которые выглядят и действуют подобно таблице, но в действительности являются результатами запросов. Некоторые функции ограничений могут также выполняться представлениями, так что вы сможете лучше оценить вашу потребность к ограничениям, после того, как вы прочитаете следующие три главы.</p>
<h3 id="работа-с-sql-10">РАБОТА С SQL</h3>
<ul>
<li>Создайте таблицу с именем Cityorders. Она должна содержать такие же поля onum, amt, и snum что и таблица Порядков, и такие же поля cnum и city что и таблица Заказчиков, так что порядок каждого заказчика будет вводиться в эту таблицу вместе с его городом. Поле оnum будет первичным ключом Cityorders. Все поля в Cityorders должны иметь ограничения при сравнении с таблицами Заказчиков и Порядков. Допускается, что родительские ключи в этих таблицах уже имеют соответствующие ограничения.</li>
<li>Усложним проблему. Переопределите таблицу Порядков следующим образом: добавьте новый столбец с именем prev, который будет идентифицирован для каждого порядка, поле onum предыдущего порядка для этого текущего заказчика. Выполните это с использованием внешнего ключа ссылающегося на саму таблицу Порядков. Внешний ключ должен ссылаться также на поле cnum заказчика, обеспечивающего определенную предписанную связь между текущим порядком и ссылаемым.</li>
</ul>
<h2 id="глава-20-введение-представления">Глава 20. ВВЕДЕНИЕ: ПРЕДСТАВЛЕНИЯ</h2>
<p>ПРЕДСТАВЛЕНИЕ (VIEW) - ОБЪЕКТ ДАННЫХ КОТОРЫЙ не содержит никаких данных его владельца. Это - тип таблицы, чье содержание выбирается из других таблиц с помощью выполнения запроса. Поскольку значения в этих таблицах меняются, то автоматически, их значения могут быть показаны представлением.
В этой главе, вы узнаете что такое представления, как они создаются, и немного об их возможностях и ограничениях. Использование представлений основанных на улучшеных средствах запросов, таких как обьединение и подзапрос, разработаных очень тщательно, в некоторых случаях даст больший выиигрыш по сравнениию с запросами.</p>
<h3 id="что-такое-представление">ЧТО ТАКОЕ ПРЕДСТАВЛЕНИЕ?</h3>
<p>Типы таблиц, с которыми вы имели дело до сих пор, назывались - базовыми таблицами. Это - таблицы, которые содержат данные. Однако имеется другой вид таблиц: - представления. Представления - это таблицы чье содержание выбирается или получается из других таблиц. Они работают в запросах и операторах DML точно также как и основные таблицы, но не содержат никаких собственных данных. Представления - подобны окнам, через которые вы просматриваете информацию( как она есть, или в другой форме, как вы потом увидите ), которая фактически хранится в базовой таблице. Представление - это фактически запрос, который выполняется всякий раз, когда представление становится темой команды. Вывод запроса при этом в каждый момент становится содержанием представления.</p>
<h3 id="команда-create-view">КОМАНДА CREATE VIEW</h3>
<p>Вы создаете представление командой CREATE VIEW. Она состоит из слов CREATE VIEW (СОЗДАТЬ ПРЕДСТАВЛЕНИЕ), имени представления которое нужно создать, слова AS (КАК), и далее запроса, как в следующем примере:</p>
<pre><code>CREATE VIEW Londonstaff
AS SELECT *
FROM Salespeople
WHERE city='London';
</code></pre>
<p>Теперь Вы имеете представление, называемое Londonstaff. Вы можете использовать это представление точно так же как и любую другую таблицу. Она может быть запрошена, модифицирована, вставлена в, удалена из, и соединена с, другими таблицами и представлениями. Давайте сделаем запрос такого представления (вывод показан в Таблице 20.1):</p>
<pre><code>SELECT *
FROM Londonstaff;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Londonstaff;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
<th>   comm</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1200<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   0.1100<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 20.1: Представление Londonstaff
Когда вы приказываете SQL выбрать(SELECT) все строки (* ) из представления, он выполняет запрос содержащий в определении - Loncfonstaff, и возвращает все из его вывода. Имея предикат в запросе представления, можно вывести только те строки из представления, которые будут удовлетворять этому предикату. Вы могли бы вспомнить, что в Главе 15, вы имели таблицу, называемую Londonstaff, в которую вы вставляли это же самое содержание (конечно, мы понимаем что таблица - не слишком велика. Если это так, вы будете должны выбрать другое имя для вашего представления). Преимущество использования представления, по сравнению с основной таблицы, в том, что представление будет модифицировано автоматически всякий раз, когда таблица лежащая в его основе изменяется.
Содержание представления не фиксировано, и переназначается каждый раз когда вы ссылаетесь на представление в команде. Если вы добавите завтра другого, живущего в Лондоне продавца, он автоматически появится в представлении.
Представления значительно расширяют управление вашими данными. Это - превосходный способ дать публичный доступ к некоторой, но не всей информации в таблице. Если вы хотите чтобы ваш продавец был показан в таблице Продавцов, но при этом не были показаны комиссии других продавцов, вы могли бы создать представление с использованием следующего оператора (вывод показан в Таблице 20.2 )</p>
<pre><code>CREATE VIEW Salesown
AS SELECT snum, sname, city
FROM Salespeople:
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Salesown;
</code></pre>
<table>
<thead>
<tr>
<th>   snum</th>
<th>   sname</th>
<th>   city</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1001<br style="margin: 0px; padding: 0px;"></td>
<td>   Peel<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1002<br style="margin: 0px; padding: 0px;"></td>
<td>   Serres<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1004<br style="margin: 0px; padding: 0px;"></td>
<td>   Motika<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Barcelona<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   1003<br style="margin: 0px; padding: 0px;"></td>
<td>   Axelrod<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 20.2: Представление Salesown</p>
<p>Другими словами, это представление - такое же как для таблицы Продавцов, за исключением того, что поле comm, не упоминалось в запросе, и следовательно не было включено в представление.</p>
<h3 id="модифицирование-представлений">МОДИФИЦИРОВАНИЕ ПРЕДСТАВЛЕНИЙ</h3>
<p>Представление может теперь изменяться командами модификации DML, но модификация не будет воздействовать на само представление. Команды будут на самом деле перенаправлены к базовой таблице:</p>
<pre><code>UPDATE Salesown
SET city='Palo Alto'
WHERE snum=1004;
</code></pre>
<p>Его действие идентично выполнению той же команды в таблице Продавцов. Однако, если значение комиссионных продавца будет обработано командой UPDATE</p>
<pre><code>UPDATE Salesown
SET comm=.20
WHERE snum=1004;
</code></pre>
<p>она будет отвергнута, так как поле comm отсутствует в представлении Salesown. Это важное замечание, показывающее что не все представления могут быть модифицированы. Мы будем исследовать проблемы модификации представлений в Главе 21.</p>
<h3 id="именование-столбцов">ИМЕНОВАНИЕ СТОЛБЦОВ</h3>
<p>В нашем примере, поля наших представлений имеют свои имена, полученые прямо из имен полей основной таблицы. Это удобно. Однако, иногда вам нужно снабжать ваши столбцы новыми именами:</p>
<ul>
<li>когда некоторые столбцы являются выводимыми, и проэтому не имеющими имен.</li>
<li>когда два или более столбцов в объединении, имеют те же имена что в их базовой таблице.</li>
</ul>
<p>Имена, которые могут стать именами полей, даются в круглых скобках, после имени таблиц. Они не будут запрошены, если совпадают с именами полей запрашиваемой таблицы. Тип данных и размер этих полей будут отличаются от запрашиваемых полей которые &quot;передаются&quot; в них. Обычно вы не указываете новых имен полей, но если вы все таки сделали это, вы должны делать это для каждого поля в представлении.</p>
<h3 id="комбинирование-предикатов-представлений-и-основных-запросов-в-представлениях">КОМБИНИРОВАНИЕ ПРЕДИКАТОВ ПРЕДСТАВЛЕНИЙ И ОСНОВНЫХ ЗАПРОСОВ В ПРЕДСТАВЛЕНИЯХ</h3>
<p>Когда вы делаете запрос представления, вы собственно, запрашиваете запрос. Основной способ для SQL обойти это, - объединить предикаты двух запросов в один. Давайте посмотрим еще раз на наше представление с именем Londonstaff :</p>
<pre><code>CREATE VIEW Londonstaff
AS SELECT *
FROM Salespeople
WHERE city='London';
</code></pre>
<p>Если мы выполняем следующий запрос в этом представлении</p>
<pre><code>SELECT *
FROM Londonstaff
WHERE comm &gt; .12;
</code></pre>
<p>он такой же как если бы мы выполнили следующее в таблице Продавцов:</p>
<pre><code>SELECT *
FROM Salespeople
WHERE city='London'
AND comm &gt; .12;
</code></pre>
<p>Это прекрасно, за исключением того, что появляется возможная проблема с представлением. Имеется возможность комбинации из двух полностью допустимых предикатов и получения предиката который не будет работать. Например, предположим что мы создаем (CREATE) следующее представление:</p>
<pre><code>CREATE VIEW Ratingcount (rating, number)
AS SELECT rating, COUNT (*)
FROM Customers
GROUP BY rating;
</code></pre>
<p>Это дает нам число заказчиков которые мы имеем для каждого уровня оценки(rating). Вы можете затем сделать запрос этого представления чтобы выяснить, имеется ли какая-нибудь оценка, в настоящее время назначенная для трех заказчиков:</p>
<pre><code>SELECT *
FROM Ratingcount
WHERE number=3;
</code></pre>
<p>Посмотрим что случится если мы скомбинируем два предиката:</p>
<pre><code>SELECT rating, COUNT (*)
FROM Customers
WHERE COUNT (*)=3
GROUP BY rating;
</code></pre>
<p>Это недопустимый запрос. Агрегатные функции, такие как COUNT (СЧЕТ), не могут использоваться в предикате. Првильным способом при формировании вышеупомянутого запроса, конечно же будет следующий:</p>
<pre><code>SELECT rating, COUNT (*)
FROM Customers
GROUP BY rating;
HAVING COUNT (*)=3;
</code></pre>
<p>Но SQL может не выполнить превращения. Может ли равноценный запрос вместо запроса Ratingcount потерпеть неудачу? Да может! Это - неоднозначная область SQL, где методика использования представлений может дать хорошие результаты. Самое лучшее что можно сделать в случае, когда об этом ничего не сказано в вашей системной документации, так это попытка в ней разобраться. Если команда допустима, вы можете использовать представления чтобы установить некоторые ограничения SQL в синтаксисе запроса.</p>
<h3 id="групповые-представления">ГРУППОВЫЕ ПРЕДСТАВЛЕНИЯ</h3>
<p>Групповные представления - это представления, наподобии запроса Ratingcount в предыдущем примере, который содержит предложение GROUP BY, или который основывается на других групповных представлениях.
Групповые представления могут стать превосходным способом обрабатывать полученную информацию непрерывно. Предположим, что каждый день вы должны следить за порядком номеров заказчиков, номерами продавцов принимающих порядки, номерами порядков, средним от порядков, и общей суммой приобретений в порядках.
Чем конструировать каждый раз сложный запрос, вы можете просто создать следующее представление:</p>
<pre><code>CREATE VIEW Totalforday
AS SELECT odate, COUNT (DISTINCT cnum), COUNT
(DISTINCT snum), COUNT (onum), AVG
(amt), SUM (amt)
FROM Orders
GROUP BY odate;
</code></pre>
<p>Теперь вы сможете увидеть всю эту информацию с помощью простого запроса:</p>
<pre><code>SELECT *
FROM Totalforday;
</code></pre>
<p>Как мы видели, SQL запросы могут дать вам полный комплекс возможностей, так что представления обеспечивают вас чрезвычайно гибким и мощным инструментом чтобы определить точно, как ваши данные могут быть использованы. Они могут также делать вашу работу более простой, переформатируя данные удобным для вас способом и исключив двойную работу.</p>
<h3 id="представления-и-обьединения">ПРЕДСТАВЛЕНИЯ И ОБЬЕДИНЕНИЯ</h3>
<p>Представления не требуют чтобы их вывод осуществлялся из одной базовой таблицы. Так как почти любой допустимый запрос SQL может быть использован в представлении, он может выводить информацию из любого числа базовых таблиц, или из других представлений. Мы можем, например, создать представление которое показывало бы, порядки продавца и заказчика по имени:</p>
<pre><code>CREATE VIEW Nameorders
AS SELECT onum, amt, a.snum, sname, cname
FROM Orders a, Customers b, Salespeople c
WHERE a.cnum=b.cnum
AND a.snum=c.snum;
</code></pre>
<p>Теперь вы можете выбрать (SELECT) все порядки заказчика или продавца (* ), или можете увидеть эту информацию для любого порядка. Например, чтобы увидеть все порядки продавца Rifkin, вы должны ввести следующий запрос (вывод показан в Таблице 20.3 ):</p>
<pre><code>SELECT *
FROM Nameorders
WHERE sname='Rifkin';
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Nameorders WHERE sname='Rifkin';
</code></pre>
<table>
<thead>
<tr>
<th>   onum</th>
<th>   amt</th>
<th>   snum</th>
<th>   sname</th>
<th>   cname</th>
</tr>
</thead>
<tbody>
<tr>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   18.69<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3006<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 20.3: Порядки Rifkin показаные в Nameorders</p>
<p>Вы можете также объединять представления с другими таблицами, или базовыми таблицами или представлениями, поэтому вы можете увидеть все порядки Axelrodа и значения его комиссиионных в каждом порядке:</p>
<pre><code>SELECT a.sname, cname, amt comm
FROM Nameorders a, Salespeople b
WHERE a.sname='Axelrod'
AND b.snum=a.snum;
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 20.4.</p>
<p>В предикате, мы могли бы написать - &quot; WHERE a.sname=|Axelrod' AND b.sname=|Axelrod| &quot;, но предикат который мы использовали здесь более общеупотребительный. Кроме того поле snum - это первичный ключ таблицы Продавцов, и следовательно должен по определению быть уникальным.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT a.sname, cname, amt * comm FROM Nameorders a, Salespeople b
WHERE a.sname='Axelrod' AND b.snum=a.snum;
</code></pre>
<table>
<thead>
<tr>
<th>   onum</th>
<th>   amt</th>
<th>   snum</th>
<th>   sname</th>
<th>   cname</th>
</tr>
</thead>
<tbody>
<tr>
<td>   3001<br style="margin: 0px; padding: 0px;"></td>
<td>   18.69<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   3006<br style="margin: 0px; padding: 0px;"></td>
<td>   1098.16<br style="margin: 0px; padding: 0px;"></td>
<td>   1007<br style="margin: 0px; padding: 0px;"></td>
<td>   Rifkin<br style="margin: 0px; padding: 0px;"></td>
<td>   Cisneros<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 20. 4: Обьединение основной таблицы с представлением</p>
<p>Если бы там например было два Axelrodf, вариант с именем, будет обединять вместе их данные. Более предпочтительный вариант - использовать поле snum чтобы хранить его отдельно.</p>
<h3 id="представления-и-подзапросы">ПРЕДСТАВЛЕНИЯ И ПОДЗАПРОСЫ</h3>
<p>Представления могут также использовать и подзапросы, включая соотнесенные подзапросы. Предположим ваша компания предусматривает премию для тех продавцов которые имеют заказчика с самым высоким порядком для любой указанной даты. Вы можете проследить эту информацию с помощью представления:</p>
<pre><code>CREATE VIEW Elitesalesforce
AS SELECT b.odate, a.snum, a.sname,
FROM Salespeople a, Orders b
WHERE a.snum=b.snum
AND b.amt=
(SELECT MAX (amt)
FROM Orders c
WHERE c.odate=b.odate);
</code></pre>
<p>Если, с другой стороны, премия будет назначаться только продавцу который имел самый высокий порядок за последние десять лет, вам необходимо будет проследить их в другом представлении основанном на первом:</p>
<pre><code>CREATE VIEW Bonus
AS SELECT DISTINCT snum, sname
FROM Elitesalesforce a
WHERE 10 &lt;=
(SELECT COUNT (*)
FROM Elitesalestorce b
WHERE a.snum=b.snum);
</code></pre>
<p>Извлечение из этой таблицы продавца, который будет получать премию - выпоняется простым вопросом:</p>
<pre><code>SELECT *
FROM Bonus;
</code></pre>
<p>Теперь мы видим истинную мощность SQL. Извлечение той же полученной информации программами RPG или COBOL будет более длительной процедурой. В SQL, это - только вопрос из двух комплексных команд, сохраненных, как представление совместно с простым запросом. При самостоятельном запросе - мы должны заботится об этом каждый день, потому что информация которую извлекает запрос, непрерывно меняется чтобы отражать текущее состояние базы данных.</p>
<h3 id="что-не-могут-делать-представления">ЧТО НЕ МОГУТ ДЕЛАТЬ ПРЕДСТАВЛЕНИЯ</h3>
<p>Имеются большое количество типов представлений (включая многие из наших примеров в этой главе ) которые являются доступными только для чтения. Это означает, что их можно запрашивать, но они не могут подвергаться действиям команд модификации. (Мы будем рассматривать эту тему в Главе 21.)
Имеются также некоторые виды запросов, которые не допустимы в определениях представлений. Одиночное представление должно основываться на одиночном запросе; ОБЪЕДИНЕНИЕ (UNION) и ОБЪЕДИНЕНИЕ ВСЕГО (UNIOM ALL) не разрешаются. УПОРЯДОЧЕНИЕ ПО(ORDER BY) никогда не используется в определении представлений. Вывод запроса формирует содержание представления, которое напоминает базовую таблицу и является - по определению - неупорядоченным.</p>
<h3 id="удаление-представлений">УДАЛЕНИЕ ПРЕДСТАВЛЕНИЙ</h3>
<p>Синтаксис удаления представления из базы данных подобен синтаксису удаления базовых таблиц:</p>
<pre><code>DROP VIEW &lt; view name &gt;
</code></pre>
<p>В этом нет необходимости, однако, сначала надо удалить все содержание как это делается с базовой таблицей, потому что содержание представления не является созданым и сохраняется в течении определеной команды. Базовая таблица из которой представление выводится, не эффективна когда представление удалено. Помните, вы должны являться владельцем представления чтобы иметь возможность удалить его.</p>
<h3 id="резюме-14">РЕЗЮМЕ</h3>
<p>Теперь, когда вы можете использовать представления, ваша способность отслеживать и обрабатывать содержание вашей базы данных, значительно расширилась. Любые вещи которые вы можете создать с запросом, вы всегда сможете определить как представление. Запросы этих представлений, фактически, запрос запроса. Использование представлений и для удобства и для защиты, также удобно как и многие возможности представлений для форматирования и получения значений из постоянно меняющегося содержания вашей базы данных. Имеется один главный вывод относительно представлений, это способность к модификации, которую мы выбрали в отличии от Главы 21. Как показано, вы можете модифицировать представления также как и базовую таблицу, с помощью изменений применяемых к таблице из которой получается представление, но это не всегда возможно.</p>
<h3 id="работа-с-sql-11">РАБОТА С SQL</h3>
<ul>
<li>Создайте представление которое бы показывало всех заказчиков которые имеют самые высокие оценки.</li>
<li>Создайте представление которое бы показывало номер продавца в каждом городе.</li>
<li>Создайте представление которое бы показывало усредненый и общий порядки для каждого продавца после его имени. Предполагается, что все имена - уникальны.</li>
<li>Создайте представление которое бы показывало каждого продавца с многочислеными заказчиками.</li>
</ul>
<h2 id="глава-21-изменение-значений-с-помощью-представлений">Глава 21. ИЗМЕНЕНИЕ ЗНАЧЕНИЙ С ПОМОЩЬЮ ПРЕДСТАВЛЕНИЙ</h2>
<p>ЭТА ГЛАВА РАССКАЗЫВАЕТ О КОМАНДАХ МОДИФИКАЦИИ ЯЗЫКА DML - ВСТАВИТЬ(INSERT), ИЗМЕНИТЬ(UPDATE), и УДАЛИТЬ(DELETE) - когда они применя ются для представлений. Как упомянуто в предыдущей главе, использование команд модификации в представлениях - это косвенный способ использования их в ссылочных таблицах с помощью запросов представлений. Однако, не все представления могут модифицироваться.
В этой главе, мы будем обсуждать правила определяющие, является ли представление модифицируемым. Кроме того, вы обучитесь использованию предложения WITH CHECK OPTION, которое управляет указанными значениями, которые можно вводить в таблицу с помощью представления.
Как упомянуто в Главе 18, это, в некоторых случаях, может быть желательным вариантом непосредственного ограничения таблицы.</p>
<h3 id="модифицирование-представления">МОДИФИЦИРОВАНИЕ ПРЕДСТАВЛЕНИЯ</h3>
<p>Один из наиболее трудных и неоднозначных аспектов представлений - непосредственное их использование с командами модификации DML. Как упомянуто в предыдущей главе, эти команды фактически воздействуют на значения в базовой таблице представления. Это является некоторым противоречием. Представление состоит из результатов запроса, и когда вы модифицируете представление, вы модифицируете набор результатов запроса. Но модификация не должна воздействовать на запрос ; она должна воздействовать на значения в таблице к которой был сделан запрос, и таким образом изменять вывод запроса. Это не простой вопрос. Следующий оператор будет создавать представление показанное в Таблице 21.1:</p>
<pre><code>CREATE VIEW Citymatch (custcity, salescity)
AS SELECT DISTINCT a.city, b.city
FROM Customers a, Salespeople b
WHERE a.snum=b.snum;
</code></pre>
<p>Это представление показывает все совпадения заказчиков с их продавцами так, что имеется по крайней мере один заказчик в городе_заказчика обслуживаемый продавцом в городе_продавца.
Например, одна строка этой таблицы - London London - показывает, что имеется по крайней мере один заказчик в Лондоне,обслуживаемый продавцом в Лондоне. Эта строка может быть произведена при совпадении Hoffmanа с его продавцом Peel, причем если оба они из Лондона.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM Citymatch;
</code></pre>
<table>
<thead>
<tr>
<th>   custcity</th>
<th>   salescity</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Berlin<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   London<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Rome<br style="margin: 0px; padding: 0px;"></td>
<td>   New York<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   Barselona<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
<td>   San Jose<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 21.1: Представление совпадения по городам
Однако, то же самое значение будет произведено при совпадении Clemens из Лондона, с его продавцом, который также оказался с именем - Peel. Пока отличающиеся комбинации городов выбирались конкретно, только одна строка из этих значений была произведена.
Даже если вы не получите выбора используя отличия, вы все еще будете в том же самом положении, потому что вы будете тогда иметь две строки в представлении с идентичными значениями, то-есть с обоими столбцами равными &quot; Lоndon London &quot;. Эти две строки представления будут отличаться друг от друга, так что вы пока не сможете сообщить, какая строка представления исходила из каких значений базовых таблиц( имейте в виду, что запросы не использующие предложение ORDER BY, производят вывод в произвольном порядке. Это относится также и к запросам используемым внутри представлений, которые не могут использовать ORDER BY. Таким образом, порядок из двух строк не может быть использован для их отличий. Это означает, что мы будем снова обращаться к выводу строк которые не могут быть точно связаны с указаными строками запрашиваемой таблицы. Что если вы пробуете удалить строку | London London | из представления? Означало бы это удаление Hoffmanа из таблицы Заказчиков, удаление Clemens из той же таблицы, или удаление их обоих? Должен ли SQL также удалить Peel из таблицы Продавцов? На эти вопросы невозможно ответить точно, поэтому удаления не разрешены в представлениях такого типа. Представление Citymatch - это пример представления только_чтение, оно может быть только запрошено, но не изменено.</p>
<h3 id="определение-модифицируемости-представления">ОПРЕДЕЛЕНИЕ МОДИФИЦИРУЕМОСТИ ПРЕДСТАВЛЕНИЯ</h3>
<p>Если команды модификации могут выполняться в представлении, представление как сообщалось будет модифицируемым; в противном случае оно предназначено только для чтения при запросе. Непротивореча этой терминологии, мы будем использовать выражение &quot;модифицируемое представление&quot;(updating a view), чтоы означает возможность выполнения в представление любой из трех команд модификации DML (Вставить, Изменить и Удалить ), которые могут изменять значения. Как вы определите, является ли представление модифицируемым? В теории базы данных, это - пока обсуждаемая тема. Основной ее принцип такой: модифицирумое представление - это представление в котором команда модификации может выполниться, чтобы изменить одну и только одну строку основной таблицы в каждый момент времени, не воздействуя на любые другие строки любой таблицы.</p>
<p>Использование этого принципа на практике, однако, затруднено. Кроме того, некоторые представления, которые являются модифицируемыми в теории, на самом деле не являются модифицируемыми в SQL. Критерии по которые определяют, является ли представление модифицируемым или нет, в SQL, следующие:</p>
<ul>
<li>Оно должно выводиться в одну и только в одну базовую таблицу.</li>
<li>Оно должно содержать первичный ключ этой таблицы (это технически не предписывается стандартом ANSI, но было бы неплохо придерживаться этому).</li>
<li>Оно не должно иметь никаких полей, которые бы являлись агрегатнымифункциями.</li>
<li>Оно не должно содержать DISTINCT в своем определении.</li>
<li>Оно не должно использовать GROUP BY или HAVING в своем определении.</li>
<li>Оно не должно использовать подзапросы (это - ANSI_ограничение которое не предписано для некоторых реализаций )</li>
<li>Оно может быть использовано в другом представлении, но это представление должно также быть модифицируемыми.</li>
<li>Оно не должно использовать константы, строки, или выражения значений (например: comm * 100 ) среди выбранных полей вывода.</li>
<li>Для INSERT, оно должно содержать любые поля основной таблицы которые имеют ограничение NOT NULL, если другое ограничение по умолчанию, не определено.</li>
</ul>
<h3 id="модифицируемые-представления-и-представления-только_чтение">МОДИФИЦИРУЕМЫЕ ПРЕДСТАВЛЕНИЯ И ПРЕДСТАВЛЕНИЯ ТОЛЬКО_ЧТЕНИЕ.</h3>
<p>Одно из этих ограничений то, что модифицируемые представления, фактически, подобны окнам в базовых таблицах. Они показывают кое-что, но не обязательно все, из содержимого таблицы. Они могут ограничивать определенные строки (использованием предикатов), или специально именованные столбцы (с исключениями ), но они представляют значения непосредственно и не выводит их информацию, с использованием составных функций и выражений.
Они также не сравнивают строки таблиц друг с другом (как в обьединениях и подзапросах, или как с DISTINCT ).
Различия между модифицируемыми представлениями и представлениями только_чтение неслучайны.
Цели для которых вы их используете, часто различны. Модифицируемые представления, в основном, используются точно так же как и базовые таблицы. Фактически, пользователи не могут даже осознать, является ли объект который они запрашивают, базовой таблицей или представлением.
Это превосходный механизм защиты для сокрытия частей таблицы, которые являются конфиденциальными или не относятся к потребностям данного пользователя. (В Главе 22, мы покажем вам, как позволить пользователям обращаться к представлению, а не к базовой таблице ).
Представления только_чтение, с другой стороны, позволяют вам получать и переформатировать данные более рационально. Они дают вам библиотеку сложных запросов, которые вы можете выполнить и повторить снова, сохраняя полученную вами информацию до последней минуты. Кроме того, результаты этих запросов в таблицах, которые могут затем использоваться в запросах самостоятельно (например, в обьединениях ) имеют преимущество над просто выполнением запросов.
Представления только_чтение могут также иметь прикладные программы защиты. Например, вы можете захотеть, чтобы некоторые пользователи видели агрегатные данные, такие как усредненное значение комиссионных продавца, не видя индивидуальных значений комиссионных.</p>
<h3 id="что-является---модифицируемыми-представлением">ЧТО ЯВЛЯЕТСЯ - МОДИФИЦИРУЕМЫМИ ПРЕДСТАВЛЕНИЕМ</h3>
<p>Имеются некоторые примеры модифицируемых представлений и представлений только_чтение:</p>
<pre><code>CREATE VIEW Dateorders (odate, ocount)
AS SELECT odate, COUNT (*)
FROM Orders
GROUP BY odate;
</code></pre>
<p>Это - представление только_чтение из-за присутствия в нем агрегатной функции и GROUP BY.</p>
<pre><code>CREATE VIEW Londoncust
AS SELECT *
FROM Customers
WHERE city='London';
</code></pre>
<p>А это - представление модифицируемое.</p>
<pre><code>CREATE VIEW SJsales (name, number, percentage)
AS SELECT sname, snum, comm 100
FROM Salespeople
WHERE city='SanJose';
</code></pre>
<p>Это - представление только_чтение из-за выражения &quot; comm * 100 &quot; . При этом, однако, возможны переупорядочение и переименование полей. Некоторые программы будут позволять удаление в этом представлении или в порядках столбцов snum и sname.</p>
<pre><code>CREATE VIEW Salesonthird
AS SELECT *
FROM Salespeople
WHERE snum IN
(SELECT snum
FROM Orders
WHERE odate=10/03/1990);
</code></pre>
<p>Это - представление только_чтение в ANSI из-за присутствия в нем подзапроса. В некоторых программах, это может быть приемлемо.</p>
<pre><code>CREATE VIEW Someorders
AS SELECT snum, onum, cnum
FROM Orders
WHERE odate IN (10/03/1990,10/05/1990);
</code></pre>
<p>Это - модифицируемое представление.</p>
<h3 id="проверка-значений-помещаемых-в-представление">ПРОВЕРКА ЗНАЧЕНИЙ ПОМЕЩАЕМЫХ В ПРЕДСТАВЛЕНИЕ</h3>
<p>Другой вывод о модифицируемости представления тот, что вы можете вводить значения которые &quot; проглатываются &quot; (swallowed) в базовой таблице. Рассмотрим такое представление:</p>
<pre><code>CREATE VIEW Highratings
AS SELECT cnum, rating
FROM Customers
WHERE rating=300;
</code></pre>
<p>Это - представление модифицируемое. Оно просто ограничивает ваш доступ к определенным строкам и столбцам в таблице. Предположим, что вы вставляете (INSERT) следующую строку:</p>
<pre><code>INSERT INTO Highratings
VALUES (2018, 200);
</code></pre>
<p>Это - допустимая команда INSERT в этом представлении. Строка будет вставлена, с помощью представления Highratings, в таблицу Заказчиков.
Однако когда она появится там, она исчезнет из представления, поскольку значение оценки не равно 300. Это - обычная проблема.
Значение 200 может быть просто напечатано, но теперь строка находится уже в таблице Заказчиков где вы не можете даже увидеть ее. Пользователь не сможет понять, почему введя строку он не может ее увидеть, и будет неспособен при этом удалить ее. Вы можете быть гарантированы от модификаций такого типа с помощью включения WITH CHECK OPTION (С ОПЦИЕЙ ПРОВЕРКИ) в определение представления. Мы можем использовать WITH CHECK OPTION в определении представления Highratmgs.</p>
<pre><code>CREATE VIEW Highratings
AS SELECT cnum, rating
FROM Customers
WHERE rating=300
WITH CHECK OPTION;
</code></pre>
<p>Вышеупомянутая вставка будет отклонена.
WITH CHECK OPTION - производит действие все_или_ничего (all-or-nothing). Вы помещаете его в определение представления, а не в команду DML, так что или все команды модификации в представлении будут проверяться, или ни одна не будет проверена. Обычно вы хотите использовать опцию проверки, используя ее в определении представления, что может быть удобно.
В общем, вы должны использовать эту опцию, если у вас нет причины, разрешать представлению помещать в таблицу значения, которые он сам не может содержать.</p>
<h3 id="предикаты-и-исключенные-поля">ПРЕДИКАТЫ И ИСКЛЮЧЕННЫЕ ПОЛЯ</h3>
<p>Похожая проблема, которую вы должны знать, включает в себя вставку строк в представление с предикатом, базирующемся на одном или более исключенных полей. Например, может показаться разумным, чтобы создать Londonstaff подобно этому:</p>
<pre><code>CREATE VIEW Londonsta1t
AS SELECT snum, sname, comm
FROM Salespeople
WHERE city='London';
</code></pre>
<p>В конце концов, зачем включать значение city, если все значения city будут одинаковыми.
А как будет выглядит картинка получаемая всякий раз, когда мы пробуем вставить строку. Так как мы не можем указать значение city как значение по умолчанию, этим значением вероятно будет NULL, и оно будет введено в поле city (NULL используется если другое значение по умолчанию значение не было определено. См. Главу 18 для подробностей ).
Так как в этм случае поле city не будет равняться значению London, вставляемая строка будет исключена из представления.
Это будет верным для любой строки которую вы попробуете вставить в просмотр Londonstaff. Все они должны быть введены с помощью представления Londonstaff в таблицу Продавцов, и затем исключены из самого представления( если определением по умолчанию был не London, то это особый случай). Пользователь не сможет вводить строки в это представление, хотя все еще неизвестно, может ли он вводить строки в базовую таблицу. Даже если мы добавим WITH CHECK OPTION в определение представления</p>
<pre><code>CREATE VIEW Londonstate
AS SELECT snum, sname, comm
FROM Salespeople
WHERE city='London'
WITH CHECK OPTION;
</code></pre>
<p>проблема не обязательно будет решена. В результате этого мы получим представление которое мы могли бы модифицировать или из которого мы могли бы удалять, но не вставлять в него. В некоторых случаях, это может быть хорошо; хотя возможно нет смысла пользователям имеющим доступ к этому представлению иметь возможность добавлять строки. Но вы должны точно определить что может произойти прежде, чем вы создадите такое представление.
Даже если это не всегда может обеспечить Вас полезной информацией, полезно включать в ваше представление все поля, на которые имеется ссылка в предикате. Если вы не хотите видеть эти поля в вашем выводе, вы всегда сможете исключить их из запроса в представлении, в противоположность запросу внутри представления. Другими словами, вы могли бы определить представление Londonstaff подобно этому:</p>
<pre><code>CREATE VIEW Londonstaff
AS SELECT *
FROM Salespeople
WHERE city='London'
WITH CHECK OPTION;
</code></pre>
<p>Эта команда заполнит представление одинаковыми значениями в поле city, которые вы можете просто исключить из вывода с помощью запроса в котором указаны только те поля которые вы хотите видеть</p>
<pre><code>SELECT snum, sname, comm
FROM Londonstaff;
</code></pre>
<h3 id="проверка-представлений-которые-базируются-на-других-представлениях">ПРОВЕРКА ПРЕДСТАВЛЕНИЙ КОТОРЫЕ БАЗИРУЮТСЯ НА ДРУГИХ ПРЕДСТАВЛЕНИЯХ</h3>
<p>Еще одно надо упоминуть относительно предложения WITH CHECK OPTION в ANSI: оно не делает каскадированного изменения : Оно применяется только в представлениях в которых оно определено, но не в представлениях основанных на этом представлении. Например, в предыдущем примере</p>
<pre><code>CREATE VIEW Highratings
AS SELECT cnum, rating
FROM Customers
WHERE rating=300
WITH CHECK OPTION;
</code></pre>
<p>попытка вставить или модифицировать значение оценки не равное 300 потерпит неудачу. Однако, мы можем создать второе представление (с идентичным содержанием ) основанное на первом:</p>
<pre><code>CREATE VIEW Myratings
AS SELECT *
FROM Highratings;
</code></pre>
<p>Теперь мы можем модифицировать оценки не равные 300:</p>
<pre><code>UPDATE Myratings
SET rating=200
WHERE cnum=2004;
</code></pre>
<p>Эта команда выполняемая так как если бы она выполнялась как первое представление, будет допустима. Предложение WITH CHECK OPTION просто гарантирует, что любая модификация в представлении, произведет значения, которые удовлетворяют предикату этого представления. Модификация других представлений базирующихся на первом текущем, является все еще допустимой, если эти представления не защищены предложениями WITH CHECK OPTION внутри этих представлений. Даже если такие предложения установлены, они проверяют только те предикаты представлений в которых они содержатся. Так например, даже если представление Myratings создавалось следующим образом</p>
<pre><code>CREATE VIEW Myratings
AS SELECT *
FROM Highratings
WITH CHECK OPTION;
</code></pre>
<p>проблема не будет решена. Предложение WITH CHECK OPTION будет исследовать только предикат представления Myratings. Пока у Myratings, фактически, не имеется никакого предиката, WITH CHECK OPTION ничего не будет делать. Если используется предикат, то он будет проверяться всякий раз, когда представление Myratings будет модифицироваться, но предикат Highratings все равно будет проигнорирован. Это - дефект в стандарте ANSI, который у большинство программ исправлен. Вы можете попробовать использовать представление наподобии последнего примера и посмотреть избавлена ли ваша система от этого дефекта. (Попытка выяснить это самостоятельно может быть иногда быть проще и яснее, чем поиск ответа в документации системы. )</p>
<h3 id="резюме-15">РЕЗЮМЕ</h3>
<p>Вы теперь овладели знаниями о представлениях полностью. Кроме правил определяющих, является ли данное представление модифицируемыми в SQL, вы познакомились с основными понятиями на которых эти правила базируются - т.е что модификации в представлениях допустимы только когда SQL может недвусмысленно определить, какие значения базовой таблицы можно изменять.</p>
<p>Это означает что команда модификации, при выполнении, не должна требовать ни изменений для многих строк сразу, ни сравнений между многочисленными строками либо базовой таблицы либо вывода запроса. Так как обьединения включают в себя сравнение строк, они также запрещены. Вы также поняли различие между некоторыми способами которые используют модификацируемые представления и представления только_чтение. Вы научились воспринимать модифицируемые представления как окна, отображающие данные одиночной таблицы, но необязательно исключающие или реорганизующие столбцы, посредством выбора только определенных строк отвечающих условию предиката. Представления только_чтение, с другой стороны, могут содержать более допустимые запросы SQL; они могут следовательно стать способом хранения запросов, которые вам нужно часто выполнять в неизменной форме. Кроме того, наличие запроса чей вывод обрабатывается как объект данных, дает вам возможность иметь ясность и удобство при создании запросов в выводе запросов. Вы теперь можете предохранять команды модификации в представлении от создания строк в базовой таблице, которые не представлены в самом представлении с помощью предложения WITH CHECK OPTION в определении представления. Вы можете также использовать WITH CHECK OPTION как один из способов ограничения в базовой таблице. В автономных запросах, вы обычно используете один или более столбцов в предикате не представленых среди выбранных для вывода, что не вызывает никаких проблем. Но если эти запросы используются в модифицируемых представлениях, появляются проблемы, так как эти запросы производят представления, которые не могут иметь вставляемых в них
строк. Вы видели некоторые подходы к этим проблемам. В Главах 20 И 21, мы говорили, что представления имеют прикладные программы защиты. Вы можете позволить пользователям обращаться к представлениям не разрешая в тоже время обращаться к таблицам в которых эти представления непосредственно находятся. Глава 22 будет исследовать вопросы доступа к объектам данных в SQL.
РАБОТА С SQL</p>
<p>Какое из этих представлений - модифицируемое?
.</p>
<pre><code>CREATE VIEW Dailyorders
AS SELECT DISTINCT cnum, snum, onum, odate
</code></pre>
<p>.</p>
<pre><code>FROM Orders;
CREATE VIEW Custotals
AS SELECT cname, SUM (amt)
FROM Orders, Customers
WHERE Orders.cnum=customer.cnum
</code></pre>
<p>.</p>
<pre><code>GROUP BY cname;
CREATE VIEW Thirdorders
AS SELECT *
FROM Dailyorders
</code></pre>
<p>.</p>
<pre><code>WHERE odate=10/03/1990;
CREATE VIEW Nullcities
AS SELECT snum, sname, city
FROM Salespeople
WHERE city IS NULL
</code></pre>
<p>.</p>
<pre><code>OR sname BETWEEN 'A' AND 'MZ';
</code></pre>
<ul>
<li>Создайте представление таблицы Продавцов с именем Commissions (Комиссионные). Это представление должно включать только поля comm и snum. С помощью этого представления, можно будет вводить или изменять комиссионные, но только для значений между .10 и .20.</li>
<li>Некоторые SQL реализации имеют встроенную константу представляющую текущую дату, иногда называемую &quot; CURDATE &quot;. Слово CURDATE может следовательно использоваться в операторе SQL, и заменяться текущей датой, когда его значение станет доступным с помощью таких команд как SELECT или INSERT. Мы будем использовать представление таблицы Порядков с именем Entryorders для вставки строк в таблицу Порядков. Создайте таблицу порядков, так чтобы CURDATE автоматически вставлялась в поле odate если не указано другого значения. Затем создайте представление Entryorders, так чтобы значения не могли быть указаны.</li>
</ul>
<h2 id="глава-22-кто-что-может-делать-в-базе-данных">Глава 22. КТО ЧТО МОЖЕТ ДЕЛАТЬ В БАЗЕ ДАННЫХ</h2>
<p>В ЭТОЙ ГЛАВЕ, ВЫ ОБУЧИТЕСЬ РАБОТЕ С ПРИВИЛЕГИЯМИ. Как сказано в Главе 2, SQL используется обычно в средах, которые требуют распознавания пользователей и различия между различными пользователями систем. Вообще говоря, администраторы баз данных, сами создают пользователей и дают им привилегии. С другой стороны пользователи которые создают таблицы, сами имеют права на управление этими таблицами. Привилегии - это то, что определяет, может ли указаный пользователь выполнить данную команду. Имеется несколько типов привилегий, соответствующих нескольким типам операций. Привилегии даются и отменяются двумя командами SQL: - GRANT (ДОПУСК) и REVOKE (ОТМЕНА). Эта глава покажет вам как эти команды используются.</p>
<h3 id="пользователи">ПОЛЬЗОВАТЕЛИ</h3>
<p>Каждый пользователь в среде SQL, имеет специальное идентификационное имя или номер. Терминология везде разная, но мы выбрали (следуя ANSI) ссылку на имя или номер как на Идентификатор (ID) доступа. Команда, посланная в базе данных ассоциируется с определенным пользователем; или иначе, специальным Идентификатором доступа. Посколько это относится к SQL базе данных, ID разрешения - это имя пользователя, и SQL может использовать специальное ключевое слово USER, которое ссылается к Идентификатору доступа связанному с текущей командой. Команда интерпретируется и разрешается (или запрещается ) на основе информации связанной с Идентификатором доступа пользователя подавшего команду.</p>
<h3 id="регистрация">РЕГИСТРАЦИЯ</h3>
<p>В системах с многочислеными пользователями, имеется некоторый вид процедуры входа в систему, которую пользователь должен выполнить чтобы получить доступ к компьютерной системе. Эта процедура определяет какой ID доступа будет связан с текущим пользователем. Обычно, каждый человек использующий базу данных должен иметь свой собственный ID доступа и при регистрации превращается в действительного пользователям. Однако, часто пользователи имеющие много задачь могут регистрироваться под различными ID доступа, или наоборот один ID доступа может использоваться несколькими пользователями.
С точки зрения SQL нет никакой разницы между этими двумя случаями; он воспринимает пользователя просто как его ID доступа.
SQL база данных может использовать собственную процедуру входа в систему, или она может позволить другой программе, типа операционной системы (основная программа которая работает на вашем компьютере ), обрабатывать файл регистрации и получать ID доступа из этой программы. Тем или другим способом, но SQL будет иметь ID доступа чтобы связать его с вашими действиями, а для вас будет иметь значение ключевое слово USER.</p>
<h3 id="предоставление-привилегий">ПРЕДОСТАВЛЕНИЕ ПРИВИЛЕГИЙ</h3>
<p>Каждый пользователь в SQL базе данных имеет набор привилегий. Это - то что пользователю разрешается делать (возможно это - файл регистрации, который может рассматриваться как минимальная привилегия). Эти привилегии могут изменяться со временем - новые добавляться, старые удаляться. Некоторые из этих привилегий определены в ANSI SQL, но имеются и дополнительные привилегии, которые являются также необходимыми.
SQL привилегии как определено ANSI, не достаточны в большинстве ситуаций реальной жизни. С другой стороны, типы привилегий, которые необходимы, могут видоизменяться с видом системы которую вы используете - относительно которой ANSI не может дать никаких рекомендаций. Привилегии которые не являются частью стандарта SQL могут использовать похожий синтаксис и не полностью совпадающий со стандартом.</p>
<h3 id="стандартные-привилегии">СТАНДАРТНЫЕ ПРИВИЛЕГИИ</h3>
<p>SQL привилегии определенные ANSI - это привелегии объекта. Это означает что пользователь имеет привилегию чтобы выполнить данную команду только на определенном объекте в базе данных. Очевидно, что привилегии должны различать эти объекты, но система привилегии основанная исключительно на привилегиях объекта не может адресовывать все что нужно SQL, как мы увидем это позже в этой главе. Привилегии объекта связаны одновременно и с пользователями и с таблицами. То есть, привилегия дается определенному пользователю в указаной таблице, или базовой таблице или представлении. Вы должны помнить, что пользователь создавший таблицу (любого вида), является владельцем этой таблицы.
Это означает, что пользователь имеет все привилегии в этой таблице и может передавать привелегии другим пользователям в этой таблице. Привилегии которые можно назначить пользователю:</p>
<p><strong>SELECT</strong> Пользователь с этой привилегией может выполнять запросы в таблице.
<strong>INSERT</strong> Пользователь с этой привилегией может выполнять команду INSERT в таблице.
UPDATE Пользователь с этой привилегией может выполнять команду UPDATE на таблице. Вы можете ограничить эту привилегию для определенных столбцов таблицы.
<strong>DELETE</strong> Пользователь с этой привилегией может выполнять команду DELETE в таблице.
REFERENCES Пользователь с этой привилегией может определить внешний ключ, который использует один или более столбцов этой таблицы, как родительский ключ. Вы можете ограничить эту привилегию для определенных столбцов. (Смотрите Главу 19 для подробностей относительно внешнего ключа и родительского ключа.)</p>
<p>Кроме того, вы столкнетесь с нестандартными привилегиями объекта, такими например как INDEX (ИНДЕКС) дающим право создавать индекс в таблице, SYNONYM (СИНОНИМ) дающим право создавать синоним для объекта, который будет объяснен в Главе 23, и ALTER (ИЗМЕНИТЬ) дающим право выполнять команду ALTER TABLE в таблице. Механизм SQL назначает пользователям эти привилегии с помощью команды GRANT.
КОМАНДА GRANT
Позвольте предположить, что пользователь Diane имеет таблицу Заказчиков и хочет позволить пользователю Adrian выполнить запрос к ней.
Diane должна в этом случае ввести следующую команду:</p>
<pre><code>GRANT INSERT ON Salespeople TO Diane;
</code></pre>
<p>Теперь Adrian может выполнить запросы к таблице Заказчиков. Без других привилегий, он может только выбрать значения; но не может выполнить любое действие, которые бы воздействовало на значения в таблице Заказчиков (включая использование таблицы Заказчиков в качестве родительской таблицы внешнего ключа, что ограничивает изменения которые выполнять со значениям в таблице Заказчиков). Когда SQL получает команду GRANT, он проверяет привилегии пользователя подавшего эту команду, чтобы определить допустима ли команда GRANT.
Adrian самостоятельно не может выдать эту команду. Он также не может предоставить право SELECT другому пользователю: таблица еще принадлежит Diane (позже мы покажем как Diane может дать право Adrian предоставлять SELECT другим пользователям). Синтаксис - тот же самый, что и для предоставления других привилегий. Если Adrian - владелец таблицы Продавцов, то он может позволить Diane вводить в нее строки с помощью следующего предложения</p>
<pre><code>GRANT INSERT ON Salespeople TO Diane;
</code></pre>
<p>Теперь Diane имеет право помещать нового продавца в таблицу.
ГРУППЫ ПРИВЕЛЕГИЙ, ГРУППЫ ПОЛЬЗОВАТЕЛЕЙ
Вы не должны ограничивать себя предоставлением одиночной привилегии отдельному пользователю командой GRANT. Списки привилегий или пользователей, отделяемых запятыми, являются совершенно приемлемыми. Stephen может предоставить и SELECT и INSERT в таблице Порядков для Adrian</p>
<pre><code>GRANT SELECT, INSERT ON Orders TO Adrian;
</code></pre>
<p>или и для Adrian и для Diane</p>
<pre><code>GRANT SELECT, INSERT ON Orders TO Adrian, Diane;
</code></pre>
<p>Когда привилегии и пользователи перечислены таким образом, весь список привилегий предоставляются всем указанным пользователям. В строгой ANSI интерпретации, вы не можете предоставить привилегии во многих таблицах сразу одной командой, но в некоторых реализациях это ограничение может быть ослаблено, позволяя вам указывать несколько таблиц, отделяя их запятыми, так что бы весь список привелегий мог быть предоставлен для всех указанных таблиц.</p>
<h3 id="ограничение-привилегий-на-определенные-столбцы">ОГРАНИЧЕНИЕ ПРИВИЛЕГИЙ НА ОПРЕДЕЛЕННЫЕ СТОЛБЦЫ</h3>
<p>Все привилегии объекта используют один тот же синтаксис, кроме команд UPDATE и REGERNCES в которых необязательно указывать имена столбцов. Привилегию UPDATE можно предоставлять на подобии других привилегий:</p>
<pre><code>GRANT UPDATE ON Salespeople TO Diane;
</code></pre>
<p>Эта команда позволит Diane изменять значения в любом или во всех столбцах таблицы Продавцов. Однако, если Adrian хочет ограничить Diane в изменении например комиссионных, он может ввести</p>
<pre><code>GRANT UPDATE (comm) ON Salespeople TO Diane;
</code></pre>
<p>Другими словами, он просто должен указать конкретный столбец к которому привилегия UPDATE должна быть применена, в круглых скобках после имени таблицы. Имена многочисленых столбцов таблицы могут указываться в любом порядке, отделяемые запятыми:</p>
<p>GRANT UPDATE (city, comm) ON Salespeople TO Diane;</p>
<p>REFERENCES следует тому же самому правилу. Когда вы предоставите привилегию REFERENCES другому пользователю, он сможет создавать внешние ключи ссылающиеся на столбцы вашей таблицы как на родительские ключи. Подобно UPDATE, для привилегии REFERENCES может быть указан список из одного или более столбцов для которых ограничена эта привилегия. Например, Diane может предоставить Stephen право использовать таблицу Заказчиков, как таблицу родительского ключа, с помощью такой команды:</p>
<pre><code>GRANT REFERENCES (cname, cnum)
ON Customers TO Stephen;
</code></pre>
<p>Эта команда дает Stephen право использовать столбцы cnum и cname, в качестве родительских ключей по отношению к любым внешним ключам в его таблицах. Stephen может контролировать то как это будет выполнено. Он может определить (cname, cnum) или, как в нашем случае( cnum, cname), как двух-столбцовый родительский ключ, совпадающий с помощью внешнего ключа с двумя столбцами в одной из его собственных таблиц. Или он может создать раздельные внешние ключи чтобы ссылаться на поля индивидуально, обеспечив тем самым чтобы Diane имела принудительное присвоение родительского ключа (см. Главу 19).
Не имея ограничений на номера внешних ключей он должден базироваться на этих родительских ключах, а родительские ключи различных внешних ключей - разрешены для совмещения(overlap).
Как и в случае с привилегией UPDATE, вы можете исключить список столбцов и таким образом позволять всем без исключения столбцам быть используемыми в качестве родительских ключей. Adrian может предоставить Diane право сделать это следующей командой:</p>
<pre><code>GRANT REFERENCES ON Salespeople TO Diane;
</code></pre>
<p>Естественно, привилегия будет пригодна для использования только в столбцах, которые имеют ограничения требуемые для родительских ключей.
ИСПОЛЬЗОВАНИЕ АРГУМЕНТОВ ALL И PUBLIC
SQL поддерживает два аргумента для команды GRANT, которые имеют специальное значение: ALL PRIVILEGES (ВСЕ ПРИВИЛЕГИИ) или просто ALL и PUBLIC (ОБЩИЕ). ALL используется вместо имен привилегий в команде GRANT чтобы отдать все привилегии в таблице. Например, Diane может дать Stephen весь набор привилегий в таблице Заказчиков с помощью такой команды:</p>
<pre><code>GRANT REFERENCES ON Salespeople TO Diane;
</code></pre>
<p>(привилегии UPDATE и REFERENCES естественно применяются ко всем столбцам.) А это другой способ высказать ту же мысль:</p>
<pre><code>GRANT ALL ON Customers TO Stephen;
</code></pre>
<p>PUBLIC - больше похож на тип аргумента - захватить все (catch-all), чем на пользовательскую привилегию. Когда вы предоставляете привилегии для публикации, все пользователи автоматически их получают. Наиболее часто, это применяется для привилегии SELECT в определенных базовых аблицах или представлениях которые вы хотите сделать доступными для любого пользователя. Чтобы позволить любому пользователю видеть таблицу Порядков, вы, например, можете ввести следующее:</p>
<pre><code>GRANT SELECT ON Orders TO PUBLIC;
</code></pre>
<p>Конечно, вы можете предоставить любые или все привилегии обществу, но это видимо нежелательно. Все привилегии за исключением SELECT позволяют пользователю изменять (или, в случае REFERENCES, ограничивать) содержание таблицы. Разрешение всем пользователям изменять содержание ваших таблиц вызовет проблему. Даже если вы имеете небольшую компанию, и в ней работают все ваши текущие пользователи способные выполнять команды модификации в данной таблице, было бы лучше предоставить привилегии каждому пользователю индивидуально, чем одни и те же привелегии для всех. PUBLIC не ограничен в его передаче только текущим пользователям. Любой новый пользователь добавляемый к вашей системе, автоматически получит все привилегии назначенные ранее всем, так что если вы захотите ограничить доступ к таблице всем, сейчас или в будущем, лучше всего предоставить привилегии иные чем SELECT для индивидуальных пользователей.</p>
<h3 id="предоставление-привелегий-с-помощью-with-grant-option">ПРЕДОСТАВЛЕНИЕ ПРИВЕЛЕГИЙ С ПОМОЩЬЮ WITH GRANT OPTION</h3>
<p>Иногда, создателю таблицы хочется чтобы другие пользователи могли получить привилегии в его таблице. Обычно это делается в системах, где один или более людей создают несколько (или все) базовые таблицы в базе данных а затем передают ответственность за них тем кто будет фактически с ними работать. SQL позволяет делать это с помощью предложения WITH GRANT OPTION. Если Diane хотела бы чтобы Adrian имел право предоставлять привилегию SELECT в таблице Заказчиков другим пользователям, она дала бы ему привилегию SELECT с использованием предложения WITH GRANT OPTION:</p>
<pre><code>GRANT SELECT ON Customers TO Adrian
WITH GRANT OPTION;
</code></pre>
<p>После того Adrian получил право передавать привилегию SELECT третьим лицам; он может выдать команду</p>
<pre><code>GRANT SELECT ON Diane.Customers TO Stephen;
</code></pre>
<p>или даже</p>
<pre><code>GRANT SELECT ON Diane.Customers TO Stephen
WITH GRANT OPTION;
</code></pre>
<p>Пользователь с помощью GRANT OPTION в особой привилегии для данной таблицы, может, в свою очередь, предоставить эту привилегию к той же таблице, с или без GRANT OPTION, любому другому пользователю. Это не меняет принадлежности самой таблицы; как и прежде таблица принадлежат ее создателю. (поэтому пользователи получившие права, должны устанавливать префикс ID доступа владельца когда ссылаются к этим таблицам.
Следующая глава покажет вам этот способ. ) Пользователь же с помощью GRANT OPTION во всех привилегиях для данной таблицы будет иметь всю полноту власти в той таблице.</p>
<h3 id="отмена-привилегий">ОТМЕНА ПРИВИЛЕГИЙ</h3>
<p>Также как ANSI предоставляет команду CREATE TABLE чтобы создать таблицу, а не DROP TABLE чтобы от нее избавиться, так и команда GRANT позволяет вам давать привилегии пользователям, не предоставляя способа чтобы отобрать их обратно. Потребность удалять привилегии сводится к команде REVOKE, фактически стандартному средству с достаточно понятной формой записи. Синтаксис команды REVOKE - похож на GRANT, но имеет обратный смысл. Чтобы удалить привилегию INSERT для Adrian в таблице Порядков, вы можете ввести</p>
<pre><code>REVOKE INSERT ON Orders FROM Adrian;
</code></pre>
<p>Использование списков привилегий и пользователей здесь допустимы как и в случае с GRANT, так что вы можете ввести следующую команду:</p>
<pre><code>REVOKE INSERT, DELETE ON Customers
FROM Adrian, Stephen;
</code></pre>
<p>Однако, здесь имеется некоторая неясность. Кто имеет право отменять привилегии? Когда пользователь с правом передавать привелегии другим, теряет это право? Пользователи которым он предоставил эти привилегии, также их потеряют ? Так как это не стандартная особенность, нет никаких авторитетных ответов на эти вопросы, но наиболее общий подход - это такой: * Привилегии отменяются пользователем который их предоставил, и отмена будетт каскадироваться, то-есть она будет автоматически распространяться на всех пользователям получивших от него эту привилегию.</p>
<h3 id="использование-представлений-для-фильтрации-привелегий">ИСПОЛЬЗОВАНИЕ ПРЕДСТАВЛЕНИЙ ДЛЯ ФИЛЬТРАЦИИ ПРИВЕЛЕГИЙ</h3>
<p>Вы можете сделать действия привилегий более точными, используя представления. Всякий раз, когда вы передаете привилегию в базовой таблице пользователю, она автоматически распространяется на все строки, а при использовании возможных исключений UPDATE и REFERENCES, на все столбцы таблицы. Создавая представление которое ссылается на основную таблицу и затем переносит привилегию на представление, а не на таблицу, вы можете ограничивать эти привилегии любыми выражениями в запросе содержащимся в представлении. Это значительно улучшает базисные возможности команды GRANT.</p>
<h3 id="кто-может-создавать-представления">КТО МОЖЕТ СОЗДАВАТЬ ПРЕДСТАВЛЕНИЯ?</h3>
<p>Чтобы создавать представление, вы должны иметь привилегию SELECT во всех таблицах на которые вы ссылаетесь в представлении. Если представление - модифицируемое, любая привелегия INSERT, UPDATE, и DELETE которые вы имеете в базовой таблице, будут автоматически передаваться представлению. Если вы испытываете недостаток в привилегиях на модификацию в базовых таблицах, вы не сможете иметь их и в представлениях которые создали, даже если сами эти представления - модифицируемые.
Так как внешние ключи не используются в представлениях, привилегия REFERENCES никогда не используется при создании представлений. Все эти ограничения - определяются ANSI. Нестандартные привилегии системы (обсуждаемые позже в этой главе ) также могут быть включены. В последующих разделах мы предположим, что создатели представлений которые мы обсуждаем, имеют частные или соответствующие привилегии во всех базовых таблицах.
ОГРАНИЧЕНИЕ ПРИВИЛЕГИИ SELECT ДЛЯ ОПРЕДЕЛЕННЫХ СТОЛБЦОВ
Предположим вы хотите дать пользователю Claire способность видеть только столбцы snum и sname таблицы Продавцов. Вы можете сделать это, поместив имена этих столбцов в представление</p>
<pre><code>CREATE VIEW Clairesview
AS SELECT snum, sname
FROM Salespeople;
</code></pre>
<p>и предоставить Claire привилегию SELECT в представлении, а не в самой
таблице Продавцов:</p>
<pre><code>GRANT SELECT On Clairesview to Claire;
</code></pre>
<p>Вы можете создать привилегии специально для столбцов наподобии использования других привилегий, но, для команды INSERT, это будет означать вставку значений по умолчанию, а для команды DELETE, ограничение столбца не будет иметь значения. Привелегии REFERENCES и UPDATE, конечно, могут сделать столбцы специфическими не прибегая к представлению.</p>
<h3 id="ограничение-привелегий-для-определенных-строк">ОГРАНИЧЕНИЕ ПРИВЕЛЕГИЙ ДЛЯ ОПРЕДЕЛЕННЫХ СТРОК</h3>
<p>Обычно, более полезный способ чтобы фильтровать привилегии с представлениями - это использовать представление чтобы привилегия относилась только к определенным строкам. Вы делаете это, естественно, используя предикат в представлении который определит, какие строки являются включенными. Чтобы предоставить пользователю Adrian, привилегию UPDATE в таблице Заказчиков, для всех заказчиков размещенных в Лондоне, вы можете создать такое представление:</p>
<pre><code>CREATE VIEW Londoncust
AS SELECT *
FROM Customers
WHERE city='London'
WITH CHECK OPTION;
</code></pre>
<p>Затем Вы должны передать привилегию UPDATE в этой таблице для Adrian:</p>
<pre><code>GRANT UPDATE ON Londoncust TO Adrian;
</code></pre>
<p>В этом отличие привилегии для определенных строк от привилегии UPDATE для определенных столбцов, которая распространена на все столбцы таблицы Заказчиков, но не на строки, среди которых строки со значением поля city иным чем London не будут учитываться. Предложение WITH CHECK OPTION предохраняет Adrian от замены значения поля city на любое значение кроме London.</p>
<h3 id="предоставление-доступа-только-к-извлеченным-данным">ПРЕДОСТАВЛЕНИЕ ДОСТУПА ТОЛЬКО К ИЗВЛЕЧЕННЫМ ДАННЫМ</h3>
<p>Другая возможность состоит в том, чтобы предлагать пользователям доступ к уже извлеченным данным, а не к фактическим значениям в таблице. Агрегатные функции, могут быть весьма удобными в применении такого способа. Вы можете создавать представление которое дает счет, среднее, и общее количество для порядков на каждый день порядка:</p>
<pre><code>CREATE VIEW Datetotals
AS SELECT odate, COUNT (*), SUM (amt), AVG (amt)
FROM Orders
GROUP BY odate;
</code></pre>
<p>Теперь вы передаете пользователю Diane - привелегию SELECT в представлении Datetotals:</p>
<pre><code>GRANT SELECT ON Datetotals TO Diane;
</code></pre>
<h3 id="использование-представлений-в-качестве-альтернативы-к-ограничениям">ИСПОЛЬЗОВАНИЕ ПРЕДСТАВЛЕНИЙ В КАЧЕСТВЕ АЛЬТЕРНАТИВЫ К ОГРАНИЧЕНИЯМ</h3>
<p>Одной из последних прикладных программ из серии, описанной в Главе 18, является использование представлений с WITH CHECK OPTION как альтернативы к ограничениям. Предположим что вы хотели удостовериться, что все значения поля city в таблице Продавцов находятся в одном из городов где ваша компания в настоящее время имеет ведомство. Вы можете установить ограничение CHECK непосредственно на столбец city, но позже может стать трудно его изменить, если ваша компания например откроет там другие ведомства. В качестве альтернативы, можно создать представление, которое исключает неправильные значения city:</p>
<p>CREATE VIEW Curcities
AS SELECT *
FROM Salespeople
WHERE city IN ('London', 'Rome', 'San Jose', 'Berlin')
WITH CHECK OPTION;</p>
<p>Теперь, вместо того, чтобы предоставить пользователям привилегии модифицирования в таблице Продавцов, вы можете предоставить их в представлении Curcities. Преимущество такого подхода - в том, что если вам нужно сделать изменение, вы можете удалить это представление, создать новое, и предоставить в этом новом представлении привилегии пользователям, что проще чем изменять ограничения. Недостатком является то, что владелец таблицы Продавцов также должен использовать это представление если он не хочет чтобы его собственные команды были отклонены. С другой стороны, этот подход позволяет владельцу таблицы и любым другим получить привилегии модификации в самой таблице, а не в представлении, чтобы делать исключения для ограничений.
Это часто бывает желательно, но не выполнимо, если вы используете ограничения в базовой таблице. К сожалению, эти исключения нельзя будет увидеть в представлении. Если вы выберите этот подход, вам захочется создать второе представление, содержащее только исключения:</p>
<pre><code>CREATE VIEW Othercities
AS SELECT *
FROM Salespeople
WHERE city NOT IN ('London', 'Rome', 'San Jose',
'Berlin')
WITH CHECK OPTION;
</code></pre>
<p>Вы должны выбрать для передачи пользователям только привилегию SELECT в этом представлении, чтобы они могли видеть исключенные строки, но не могли помещать недопустимые значения city в базовую таблицу. Фактически, пользователи могли бы сделать запрос обоих представлений в объединении и увидеть все строки сразу.</p>
<h3 id="другие-типы-привилегий">ДРУГИЕ ТИПЫ ПРИВИЛЕГИЙ</h3>
<p>Вы разумеется хотите знать, кто же имеет право первым создать таблицу. Эта область привилегии не относится к ANSI, но не может игнорироваться. Все стандартные привилегии ANSI вытекают из этой привилегии; привилегии создателей таблиц которые могут передавать привилегии объекта. Если все ваши пользователи будут создавать в системе базовые таблицы с разными размерами это приведет к избыточности в них и к неэффетивности системы. Притягивают к себе и другие вопросы:</p>
<ul>
<li>Кто имеет право изменять, удалять, или ограничивать таблицы?</li>
<li>Должны ли права создания базовых таблиц отличаться от прав создания представлений?</li>
<li>Должен ли быть суперпользователь - пользователь который отвечает за поддержание базы данных и следовательно имеющий наибольшие, или все привилегии, которые не предоставляются индивидуально?</li>
</ul>
<p>Пока ANSI не принимает в этом участие, а SQL используется в различных средах, мы не можем дать окончательный ответ на эти вопросы. Мы предлагаем рассмотреть здесь кусок наиболее общих выводов.
Привилегии которые не определяются в терминах специальных объектов данных называются - привилегиями системы, или правами базы данных. На базисном уровне, они будут вероятно включать в себя право создавать объекты данных, вероятно отличающиеся от базовых таблиц( обычно создаваемыми несколькими пользователями ) и представления (обычно создаваемые большинством пользователей). Привилегии системы для создания представлений, должны дополнять, а не заменять привилегии объекта которые ANSI требует от создателей представлений (описанных ранее в этой главе). Кроме того, в системе любого размера всегда имеются некоторые типы суперпользователей - пользователей которые автоматически имеют большинство или все привилегии - и которые могут передать свой статус суперпользователя кому-нибудь с помощью привилегии или группы привилегий. Администратор Базы Данных, или DBA, является термином наиболее часто используемым для такого суперпользователя, и для привилегий которыми он обладает.</p>
<h3 id="типичные-привилегии-системы">ТИПИЧНЫЕ ПРИВИЛЕГИИ СИСТЕМЫ</h3>
<p>При общем подходе имеется три базовых привилегии системы:</p>
<ul>
<li>CONNECT (Подключить)</li>
<li>RESOURCE (Ресурс)</li>
<li>DBA (Аминистратор Базы Данных).</li>
</ul>
<p>Проще, можно сказать, что CONNECT состоит из права зарегистрироваться и права создавать представления и синонимы(см. Главу 23), если переданы привилегии объекта. RESOURCE состоит из права создавать базовые таблицы. DBA - это привилегия суперпользователя, дающая пользователю высокие полномочия в базе данных. Один или более пользователей с функциями администратора базы данных может иметь эту привилегию. Некоторые системы кроме того имеют специального пользователя, иногда называемого SYSADM или SYS (Системный Администратор Базы Данных), который имеет наивысшие полномочия; это - специальное имя, а не просто пользователь со специальной DBA привилегией. Фактически только один человек имеет право зарегистрироваться с именем SYSADM, являющимся его идентификатором доступа. Различие весьма тонкое и функционирует по разному в различных системах. Для наших целей, мы будем ссылаться на высокопривилегированного пользователя, который разрабатывает и управляет базой данных имея полномочия DBA, понимая что фактически эти полномочия - та же самая привилегия. Команда GRANT, в измененной форме, является пригодной для использования с привилегиями объекта как и с системными привилегиями. Для начала передача прав может быть сделана с помощью DBA.
Например, DBA может передать привилегию для создания таблицы пользователю Rodriguez следующим образом:</p>
<pre><code>GRANT RESOURCE TO Rodriguez;
</code></pre>
<h3 id="создание-и-удаление-пользователей">СОЗДАНИЕ И УДАЛЕНИЕ ПОЛЬЗОВАТЕЛЕЙ</h3>
<p>Естественно появляется вопрос, откуда возьмется пользователь с именем Rodriguez ? Как определить его ID допуска ? В большинстве реализаций, DBA создает пользователя, автоматически предоставляя ему привилегию CONNECT. В этом случае, обычно добавляется предложение IDENTIFIED BY, указывающее пароль. (Если же нет, операционная система должна определить, можете ли вы зарегистрироваться в базе данных с данным ID доступа. ) DBA может, например, ввести</p>
<pre><code>GRANT CONNECT TO Thelonius IDENTIFIED BY Redwagon;
</code></pre>
<p>что приведет к созданию пользователя, с именем Thelonius, даст ему право регистрироваться, и назначит ему пароль Redwagon, и все это в одном предложении.
Раз Thelonious - уже опознаный пользователь, он или DBA могут использовать эту же команду чтобы изменить пароль Redwagon. Хотя это и удобно, но все же имеются ограничения и в этом подходе. Это невозможность иметь пользователя который не мог бы зарегистрироваться, хотя бы временно. Если вы хотите запретить пользователю регистрироваться, вы должны использовать для REVOKE привилегию CONNECT, которая &quot;удаляет&quot; этого пользователя. Некоторые реализации позволяють вам создавать и удалять пользователей, независимо от их привилегий при регистрации.
Когда вы предоставляете привилегию CONNECT пользователю, вы создаете этого пользователя. При этом чтобы сделать это Вы сами, должны иметь DBA привилегию. Если этот пользователь будет создавать базовые таблицы (а не только представления ), ему нужно также предоставить привилегию RESOURCE. Но это сразу порождает другую проблему.
Если вы сделаете попытку удалить привилегию CONNECT пользователя, который имеет им созданые таблицы, команда будет отклонена, потому что ее действие оставит таблицу без владельца, а это не позволяется. Вы должны сначала удалить все таблицы созданные этим пользователем, прежде чем удалить его привилегию CONNECT . Если эти таблицы не пустые, то вы вероятно захотите передать их данные в другие таблицы с помощью команды INSERT, которая использует запрос. Вам не нужно удалять отдельно привилегию RESOURSE; достаточно удалить CONNECT чтобы удалить пользователя. Хотя все выше сказаное - это вполне стандартный подход к привилегиям системы, он также имеет значительные ограничения. Появились альтернативные подходы, которые более конкретно определены и точнее управляют привилегиями системы.
Эти выводы несколько выводят нас за пределы стандарта SQL как это определено в настоящее время, и, в некоторых реализациях, могут полностью выйти за пределы стандарта SQL. Эти вещи вероятно не будут слишком вас касаться, если вы не DBA или не пользователь высокого уровня. Обычные пользователи просто должны быть знакомыми с привилегиями системы в принципе, справляясь со своей документации только в случае специальных сообщений.</p>
<h3 id="резюме-16">РЕЗЮМЕ</h3>
<p>Привилегии дают вам возможность видеть SQL под новым углом зрения, когда SQL выполняет действия через специальных пользователей в специальной системе базы данных. Сама команда GRANT достаточно проста: с ее помощью, вы предоставляете те или иные привилегии объекта одному или более пользователям. Если вы предоставляете привилегию WITH GRANT OPTION пользователю, этот пользователь может в свою очередь предоставить эту привилегию другим. Теперь вы понимаете намеки на использование привилегий в представлениях - чтобы усовершенствовать привилегии в базовых таблицах, или как альтернативы к ограничениям - и на некоторые преимущества и недостатки такого подхода. Привилегии системы, которые необходимы, но не входят в область стандарта SQL, обсуждались в их наиболее общей форме и поэтому вы будете знакомиться с ними на практике.
Глава 23 продолжит обсуждение о выводах в SQL, таких как сохранение или восстановление изменений, создание ваших собственных имен для таблиц принадлежащих другим людям, и понимание что происходит когда различные пользователи пытаются обращаться к одному и тому же объекту одновременно.</p>
<h3 id="работа-с-sql-12">РАБОТА С SQL</h3>
<ul>
<li>Передайте Janet право на изменение оценки заказчика.</li>
<li>Передайте Stephan право передавать другим пользователям право делать запросы в таблице Порядков.</li>
<li>Отнимите привилегию INSERT( ВСТАВКА) в таблице Продавцов у Claire и у всех пользователей которым она была предоставлена.</li>
<li>Передайте Jerry право вставлять или модифицировать таблицу Заказчиков с сохранением его возможности оценивать значения в диапазоне от 100 до 500.</li>
<li>Рарешите Janet делать запросы в таблице Заказчиков, но запретите ему уменьшать оценки в той же таблице Заказчиков.</li>
</ul>
<h2 id="глава-23-глобальные-аспекты-sql">Глава 23. ГЛОБАЛЬНЫЕ АСПЕКТЫ SQL</h2>
<p>ЭТА ГЛАВА БУДЕТ ОБСУЖДАТЬ АСПЕКТЫ ЯЗЫКА SQL которые имеют отношение к базе данных как к единому целому, включая использование многочисленых имен для объектов данных, размещение запоминаемых данных, восстановлние и сохранение изменений в базе данных а также координирование одновременных действий многочисленных пользователей. Этот материал даст вам возможность конфигурации вашей базы данных, отмены действия ошибок, и определения как действия одного пользователя в базе данных будут влиять на действия других пользователей.</p>
<h3 id="переименование-таблиц">ПЕРЕИМЕНОВАНИЕ ТАБЛИЦ</h3>
<p>Каждый раз, когда вы ссылаетесь в команде к базовой таблице или представлению не являющимися вашей собственностью, вы должны установить в ней префикс имени владельца, так что бы SQL знала где ее искать. Так как это со временем становится неудобным, большинство реализаций SQL позволяют вам создавать синонимы для таблиц (что не является стандартом ANSI ) Синоним - это альтернативное имя, наподобии прозвища, для таблицы. Когда вы создаете синоним, вы становитесь его собственником, так что нет никакой необходимости, чтобы он предшествовал другому пользовательскому идентификатору доступа( имени пользователя ) Если вы имеете по крайней мере одну привилегию в одном или более столбцах таблицы; вы можете создать для них синоним. (Некоторое отношение к этому может иметь специальная привилегия для создания синонимов.)</p>
<p>Adrian может создать синоним с именем Clients, для таблицы с именем Diane.Customers, с помощью команды CREATE SYNONYM следующим образом:</p>
<pre><code>CREATE SYNONYM Clients FOR Diane.Customers;
</code></pre>
<p>Теперь, Adrian может использовать таблицу с именем Clients в команде точно так же как ее использует Diane.Customers. Синоним Clients - это собственность, используемая исключительно для Adrian.</p>
<h3 id="переименование-с-тем-же-самым-именем">ПЕРЕИМЕНОВАНИЕ С ТЕМ ЖЕ САМЫМ ИМЕНЕМ</h3>
<p>Префикс (прозвище) пользователя - это фактически часть имени любой таблицы. Всякий раз, когда вы не указываете ваше собственное имя пользователя вместе с именем вашей собственной таблицы, SQL сам заполняет для вас это место. Следовательно, два одинаковых имени таблицы но связанные с различными владельцами, становятся не идентичными и следовательно не приводят к какому-нибудь беспорядку (по крайней мере в SQL).
Это означает что два пользователя могут создать две полностью несвязанные таблицы с одинаковыми именами, но это также будет означать, что один пользователь может создать представление основанное на имени другого пользователя стоящем после имени таблицы. Это иногда делается когда представление, рассматривается как сама таблица - например, если представление просто использует CHECK OPTION как заменитель ограничения CHECK в базовой таблице( смотрите Главу 22 для подробностей). Вы можете также создавать ваши собственные синонимы, имена которых будут такими же что и первоначальные имена таблиц. Например, Adrian может определить Customers, как свой синоним для таблицы Diane.Customers :</p>
<pre><code>CREATE SYNONYM Customers FOR Diane.Customers;
</code></pre>
<p>С точки зрения SQL, теперь имеются два разных имени одной таблицы:
Diane.Customers и Adrian.Customers. Однако, каждый из этих пользователей может ссылаться к этой таблице просто как к Customers, SQL как говорилось выше сам добавит к ней недостающие имена пользователей.</p>
<h3 id="одно-имя-для-каждого">ОДНО ИМЯ ДЛЯ КАЖДОГО</h3>
<p>Если вы планируете иметь таблицу Заказчиков используемую большим числом пользователей, лучше всего что бы они ссылались к ней с помощью одного и того же имени. Это даст вам возможность, например, использовать это имя в вашем внутреннем общении без ограничений. Чтобы создать единое имя для всех пользователей, вы создаете общий синоним. Например, если все пользователи будут вызывать таблицу Заказчиков с именем Customers, вы можете ввести</p>
<pre><code>CREATE PUBLIC SYNONYM Customers FOR Customers;
</code></pre>
<p>Мы пронимаем, что таблица Заказчиков это ваша собственность, поэтому никакого префикса имени пользователя в этой команды не указывается. В основном, общие синонимы создаются владельцами объектов или привилегированными пользователями, типа DBA. Пользователям кроме того, должны еще быть предоставлены привилегии в таблице Заказчиков чтобы они могли иметь к ней доступ. Даже если имя является общим, сама таблица общей не является. Общие синонимы становятся собственными с помощью команды PUBLIC, а не с помощью их создателей.</p>
<h3 id="удаление-синонимов">УДАЛЕНИЕ СИНОНИМОВ</h3>
<p>Общие и другие синонимы могут удаляться командой DROP SYNONYM. Синонимы удаляются их владельцами, кроме общих синонимов, которые удаляются соответствующими привилегированными личностями, обычно DBA. Чтобы удалить например синоним Clients, когда вместо него уже появился общий синоним Customers, Adrian может ввести</p>
<pre><code>DROP SYNONYM Clients;
</code></pre>
<p>Сама таблица Заказчиков, естественно, становится не эффективной.
КАК БАЗА ДАННЫХ РАСПРЕДЕЛЕНА ДЛЯ ПОЛЬЗОВАТЕЛЕЙ?
Таблицы и другие объекты данных сохраняются в базе данных и находятся там связанными с определенными пользователями которые ими владеют.
В некотором смысле, вы могли бы сказать, что они сохраняются в &quot; именной области пользователя &quot;, хотя это никак не отражает их физического расположения, но зато, как и большинство вещей в SQL, находятся в строгой логической конструкции. Однако, на самом деле, объекты данных сохраняться, в физическом смысле, и количество памяти которое может использоваться определенным объектом или пользователем, в данное время, имеют свой предел.
В конце концов, никакой компьютер не имеет прямого доступа к бесконечному числу аппаратных средств (диску, ленте, или внутренней памяти) для хранения данных. Кроме того, эффективность SQL расширится если логическая структура данных будет отображаться неким физическим способом при котором эти команды получать преимущество.
В больших SQL системах, база данных будет разделена на области, так называемые Области Базы Данных или Разделы.
Это области сохраняемой информации, которые размещены так, чтобы информация внутри них находилась близко друг к другу для выполнения команд; то-есть программа не должна искать где-то далеко информацию, сгруппированную в одиночной области базы данных. Хотя ее физические возможности зависят от аппаратного оборудования, целесообразно чтобы команда работала в этих областях внутри самой SQL. Системы которые используют области базы данных (в дальнейшем называемых - DBS (Data Base Spaces)), позволяют вам с помощью команд SQL обрабатывать эти области как объекты.
DBS создаются командами CREATE DBSPACE (СОЗДАТЬ DBS), ACQUIRE DBSPACE(ПОЛУЧИТЬ DBS) или CREATE TABLESPACE (СОЗДАТЬ ТАБЛИЧНУЮ ОБЛАСТЬ), в зависимости от используемой реализации. Одна DBS может вмещать любое число пользователей, и отдельный пользователь может иметь доступ к многим DBS. Привилегия создавать таблицы, хотя и может быть передана по всей базу данных, часто передается в конкретной DBS. Мы можем создать DBS с именем Sampletables, следующей командой:</p>
<pre><code>CREATE DBSPACE Sampletables
( pctindex 10,
pctfree 25);
</code></pre>
<p>Параметр pctindex определяет какой процент DBS должен быть оставлен, чтобы сохранять в нем индексы таблиц. Pctfree - это процент DBS который оставлен чтобы позволить таблицам расширять размеры их строк (AL- TER TABLE может добавлять столбцы или увеличивать размер столбцов, делая каждую строку длиннее. Это - расширение памяти отводимой для этого). Имеются также другие параметры которые вы также можете определять, и которые меняются от программы к программе. Большинство программ автоматически будут обеспечивать значения по умолчанию, поэтому вы можете создавать DBS не определяя эти параметры. DBS может иметь или определенное ограничение размера, или ей может быть позволено расти неограниченно вместе с таблицами. Если DBS создалась, пользователям предоставляются права создавать в ней объекты. Вы можете например предоставить Diane право создать таблицу Sampletables с помощью следующей команды:</p>
<pre><code>GRANT RESOURCE ON Sampletables TO Diane;
</code></pre>
<p>Это даст вам возможность более конкретно определять место хранения данных. Первый DBS назначаемый данному пользователю - обычно тот, где все объекты этого пользователя создаются по умолчанию. Пользователи имеющие доступ к многочисленым DBS могут определить, где они хотят разместить определенный объект. При разделении вашей базы данных на DBSы, вы должны иметь в виду типы операций, которые вы будете часто выполнять. Таблицы которые, как вам уже известно, будут часто объединяться, или которые имеют одну таблицу ссылающуюся на другую во внешнем ключе, должны находиться вместе в одной DBS.
Например, вы могли бы сообщить при назначении типовых таблиц, что таблица Порядков будет часто объединяться с одной или обеими из двух других таблиц,, так как таблица Порядков использует значения из обеих этих таблиц. При прочих равных условиях, эти три таблицы должны входить в ту же самую область DBS, независимо от того, кто их владелец.
Возможное присутствие ограничения внешнего ключа в таблице Порядков, просто приведет к более строгому совместному использованию области DBS.</p>
<h3 id="когда-сделанные-изменения-становятся-постоянными">КОГДА СДЕЛАННЫЕ ИЗМЕНЕНИЯ СТАНОВЯТСЯ ПОСТОЯННЫМИ?</h3>
<p>Визуально, среда базы данных, это картина которая постоянно отображает для существующих пользователей, постоянно вводимые и изменяемые данные, допуская, что если система правильно разработана, она будет функционировать без сбоев. Однако реально, благодаря человеческим или компьютерным сбоям, ошибки время от времени случаются, и поэтому хорошие компьютерные программы стали применять способы отмены действий вызвавших такие ошибки. Команда SQL, которая воздействует на содержание или структуру базы данных - например команда модификации DML или команда DROP TABLE, - не обязательно будет необратимой. Вы можете определить после окончания ее действия, останутся ли изменения сделанные данной командой или группой команд постоянными в базы данных, или онибудут полностью проигнорированы. С этой целью, команды обрабатываются группами, называемыми - транзакциями. Транзакция начинается всякий раз, когда вы начинаете сеанс с SQL. Все команды которые вы введете будут частью этой транзакции, пока вы не завершите их вводом команды COMMIT WORK или команды ROLLBACK WORK. COMMIT может сделать все изменения постоянными с помощью транзакции, а ROLLBACK может откатить их братно или отменить. Новая транзакция начинается после каждой команды COMMIT или ROLLBACK. Этот процесс известен как диалоговая обработка запросов или транзакция. Синтаксис, чтобы оставить все ваши изменения постоянными во время регистрации, или во время последнего COMMIT или ROLLBACK</p>
<pre><code>COMMIT WORK;
</code></pre>
<p>Синтаксис отмены изменения -</p>
<pre><code>ROLLBACK WORK;
</code></pre>
<p>В большинстве реализаций, вы можете установить параметр, называемый AUTOCOMMIT. Он будет автоматически запоминать все действия которые будут выполняться. Действия которые приведут к ошибке, всегда будут автоматически &quot;прокручены&quot; обратно. Если это предусмотрено в вашей системе, для фиксации всех ваших действий, вы можете использовать эту возможность с помощью команды типа:</p>
<pre><code>SET AUTOCOMMIT ON;
</code></pre>
<p>Вы можете вернуться к обычной диалоговой обработке запросов с помощью такой команды:</p>
<pre><code>SET AUTOCOMMIT OFF;
</code></pre>
<p>Имеется возможность установки AUTOCOMMIT которую система выполнит автоматически при регистрации. Если сеанс пользователя завершается аварийно - например, произошел сбой системы или выполнена перезагрузка пользователя, - то текущая транзакция выполнит автоматический откат изменений. Это - одна из причин, по которой вы можете управлять выпонением вашей диалоговой обработки запросов, разделив ваши команды на большое количество различных транзакций. Одиночная транзакция не должна содержать много несвязанных команд; фактически, она может состоять из единственной команды. Транзакции которые включают всю группу несвязанных изменений не оставляют вам фактически никакого выбора сохранить или отклонить целую группу, если вы хотите отменить только одно определенное изменение. Хорошим правилом которому надо следовать, это делать ваши транзакции состоящими из одной команды или нескольких близко связанных команд. Например, предположим вы хотите удалить продавца Motika из базы данных. Прежде, чем вы удалите его из таблицы Продавцов, вы сначала должны сделать что-нибудь с его порядками и его заказчиками. (Если используются ограничения внешнего ключа, и ваша система, следуя ANSI, ограничивает изменение родительского ключа, у вас не будет выбора делать или не делать этого. Это будет сделано обязательно.)
Одно из логических решений, будет состоять в том, чтобы установить поле snum в его порядках в NULL, в следствии чего ни один продавец не получит комиссионные в этих порядках, пока комиссионые не будут предоставлены заказчикам для Peel. Затем вы можете удалить их из таблицы Продавцов:</p>
<pre><code>UPDATE Orders
SET snum=NULL
WHERE snum=1004;

UPDATE Cudomers
SET snum=1001
WHERE snum=1004;

DELETE FROM Salespeople
WHERE snum=1004;
</code></pre>
<p>Если у вас проблема с удалением Motika (возможно имеется другой внешний ключ ссылающийся на него о котором вы не знали и не учитывали ), вы могли бы отменить все изменения которые вы сделали, до тех пор пока проблема не будет определена и решена.
Более того, это должна быть группа команд, чтобы обрабатывать ее как одиночную транзакцию. Вы можете предусмотреть это с помощью команды COMMIT, и завершить ее с помощью команды COMMIT или ROLLBACK.</p>
<h3 id="как-sql-общается-сразу-со-многими-пользователями">КАК SQL ОБЩАЕТСЯ СРАЗУ СО МНОГИМИ ПОЛЬЗОВАТЕЛЯМИ</h3>
<p>SQL часто используется в многопользовательских средах - в средах, где сразу много пользователей могут выполнять действия в базе данных одновременно. Это создает потенциальную возможность конфликта между различными выполняемыми действиями. Например, предположим что вы выполняете команду в таблице Продавцов :</p>
<pre><code>UPDATE Salespeople
SET comm=comm * 2
WHERE sname LIKE 'R%';
</code></pre>
<p>и в это же время, Diane вводит такой запрос:</p>
<pre><code>SELECT city, AVG (comm)
FROM Salespeople
GROUP BY city;
</code></pre>
<p>Может ли усредненное значение(AVG) Diane отазить изменения которые вы делаете в таблице? Не важно, будет это сделано или нет, а важно что бы были отражены или все или ни одно из значений комиссионных (comm) для которых выполнялись изменения. Любой промежуточный результат является случайным или непредсказуемым, для порядка в котором значения были изменены физически. Вывод запроса, не должен быть случайным и непредсказуемым. Посмотрим на это с другой стороны. Предположим, что вы находите ошибку и прокручиваете обратно все ваши модификации уже после того, как Diane получила их результаты в виде вывода. В этом случае Diane получит ряд усредненых значений основанных на тех изменениях которые были позже отменены, не зная что ее информации неточна. Обработка одновременных транзакций называется - параллелизмом или совпадением, и имеет номера возможных проблем которые могут при этом возникать.
Имеются следующие примеры:</p>
<ul>
<li>Модификация может быть сделана без учета другой модификации. Например, продавец должен сделать запрос к таблице инвентаризации, чтобы найти десять фрагментов пунктов торговцев акциями, и упорядочить шесть из их для заказчика. Прежде, чем это изменение было сделано, другой продавец делает запрос к таблице и упорядочивает семь из тех же фразментов для своего заказчика. ПРИМЕЧАНИЕ: Термин &quot;упорядочить&quot;, аналогичен общепринятому - &quot;заказать&quot;, что в принципе более соответствует логике запроса, потому что с точки зрения пользователя, он именно &quot;заказывает&quot; информацию в базе данных, которая упорядочивает эту информацию в соответствии с &quot;заказом&quot;.</li>
<li>Изменения в базе данных могут быть прокручены обратно уже после того, как их действия уже были закончены. Например если Вы отменили вашу ошибку уже после того, как Diane получила свой вывод.</li>
<li>Одно действие может воздействовать частично на результат другого действия. Например когда Diane получает среднее от значений в то время как вы выполняете модификацию этих значений. Хотя это не всегда проблематично, в большинстве случаев действие такое же как если бы агрегаты должны были отразить состояние базы данных в пункте относительной стабильности. Например в ревизионных книгах, должна быть возможность вернуться назад и найти это существующее усредненное значение для Diane в некоторой временной точке, и оставить его без изменений которые можно было бы сделаны начиная уже с этого места. Это будет невозможно сделать, если модификация была выполнена во время вычисления функции.</li>
<li>Тупик. Два пользователя могут попытаться выполнить действия которые конфликтуют друг с другом. Например, если два пользователя попробуют изменить и значение внешнего ключа и значение родительского ключа одновременно.</li>
</ul>
<p>Имеется много сложнейших сценариев которые нужно было бы последовательно просматривать, если бы одновременные транзакции были неуправляемыми. К счастью, SQL обеспечивает вас средством управления параллелизмом для точного указания места получения результата. Что ANSI указывает для управления параллелизмом -это что все одновременные команды будут выполняться по принципу - ни одна команда не должна быть выдана, пока предыдущая не будет завершена (включая команды COMMIT или ROLLBACK ).
Более точно, нужно просто не позволить таблице быть доступной более чем для одной транзакции в данный момент времени. Однако в большинствситуаций, необходимость иметь базу данных доступную сразу многим пользователям, приводит к некоторому компромису в управлении параллелизмом. Некоторые реализации SQL предлагают пользователям выбор, позволяя им самим находить золотую середину между согласованностью данных и доступностью к базе данных. Этот выбор доступен пользователю, DBA, или тому и другому.
На самом деле они осуществляют это управление вне SQL, даже если и воздействуют на процесс работы самой SQL.
Механизм используемый SQL для управления параллелизмом операций, называется - блокировкой. Блокировки задерживают определенные операции в базе данных, пока другие операции или транзакции не завершены. Задержанные операции выстраиваюится в очередь и выполняются только когда блокировка снята (некоторые инструменты блокировок дают вам возможность указывать NOWAIT, которая будет отклонять команду вместо того чтобы поставить ее в очередь, позволяя вам делать что-нибудь другое).
Блокировки в многопользовательских системах необходимы. Следовательно, должен быть некий тип схемы блокировки по умолчанию, который мог бы применяться ко всем командам в базе данных. Такая схема по умолчанию, может быть определена для всей базы данных, или в качестве параметра в команде CREATE DBSPACE или команде ALTER DBSPACE, и таким образом использовать их по разному в различных DBS. Кроме того, системы обычно обеспечиваются неким типом обнаружителя зависания, который может обнаруживать ситуации, где две операции имеют блокировки, блокирующие друг друга. В этом случае, одна из команд будет прокручена обратно и получит сброс блокировки. Так как терминология и специфика схем блокировок меняются от программы к программе, мы можем смоделировать
наши рассуждения на примере программы базы данных DB2 фирмы IBM. IBM - лидер в этой области (как впрочим и во многих других ), и поэтому такой подход наиболее удобен. С другой стороны, некоторые реализации могут иметь значительные различия в синтаксисе и в функциях, но в основном их действия должно быть очень похожими.</p>
<h3 id="типы-блокировок">ТИПЫ БЛОКИРОВОК</h3>
<p>Имеется два базовых типа блокировок:</p>
<ul>
<li>распределяемые блокировки и</li>
<li>специальльные блокировки.
Распределяемые (или S-блокировки ) могут быть установлены более чем однимо пользователя в данный момент времени. Это дает возможность любому числу пользователей обращаться к данным, но не изменять их.
Специальные блокировки (или X-блокировки ) не позволяют никому вообще, кроме владельца этой блокировки обращаться к данным. Специальные блокировки используются для команд которые изменяют содержание или структуру таблицы. Они действуют до конца транзакции.
Общие блокировки используются для запросов. Насколько они продолжительны зависит фактически от уровня изоляции.
Что такое уровень изоляции блокировки? Это - то, что определяет, сколько таблиц будет блокировано. В DB2, имеется три уровня изоляции, два из которых можно применить и к распределеным и к специальным блокировкам, а третий, ограниченный, чтобы использовать эти блокировки совместно. Они управляются командами поданными извне SQL, так что мы можем обсуждать не указывая их точного синтаксиса. Точный синтаксис команд связанных с блокировками различен для различных реализаций.
Следующее обсуждение полезно прежде всего на концептуальном уровне.
Уровень изоляции - повторное чтение - гарантирует, что внутри данной транзакции, все записи извлеченные с помощью запросов, не могут быть изменены. Поскольку записи модифицируемые в транзакции являются субъектами специальной блокировки, пока транзакция не завершена, они не могут быть изменены в любом случае. С другой стороны для запросов, повторное чтение означает, что вы можете решить заранее, какие строки вы хотите заблокировать и выполнить запрос который их выберет. Выполняя запроса, вы гарантированы, что никакие изменения не будут сделаны в этих строках, до тех пор пока вы не завершите текущую транзакцию.
В то время как повторное чтение защищает пользователя, который поместил блокировку, она может в то же время значительно снизить производительность.
Уровень указатель стабильности - предохраняет каждую запись от изменений, на время когда она читается или от чтения на время ее изменения. Последний случай это специальная блокировка, и применяется пока изменение не завершено или пока оно не отменено( т.е. на время отката изменения). Следовательно, когда вы модифицируете группу записей использующих указатель стабильности, эти записи будут заблокированы пока транзакция не закончится, что аналогично действию производимому уровнем повторное чтение. Различиие между этими двумя уровнями в их воздействии на запросы. В случае уровня указатель стабильности, строки таблицы которые в данное время не используются запросом, могут быть изменены. Третий уровень изоляции DB2 - это уровень только чтение.
Только чтение фиксирует фрагмент данных; хотя на самом деле он блокирует всю таблицу. Следовательно, он не может использоваться с командами модификации. Любое содержание таблицы как единое целое, в момент выполнения команды, будет отражено в выводе запроса.
Это не обязательно так как в случае с уровнем указатель стабильности. Блокировка только чтение, гарантирует что ваш вывод будет внутренне согласован, если конечно нет необходимости во второй блокировке, не связывающей большую часть таблицы с уровнем повторное чтение. Блокировка только чтение удобна тогда, когда вы делаете отчеты, которые должны быть внутренне согласованны, и позволять доступ к большинству или ко всем строкам таблицы, не связывая базу данных.</li>
</ul>
<h3 id="другие-способы-блокировки-данных">ДРУГИЕ СПОСОБЫ БЛОКИРОВКИ ДАННЫХ</h3>
<p>Некоторые реализации выполняют блокировку страницы вместо блокировки строки. Это может быть либо возможностю для вашего управления либо нечто заложенным уже в конструкцию системы.
Страница - это блок накопления памяти, обычно равный 1024 байт.
Страница может состоять из одной или более строк таблицы, возможно сопровождаемых индексами и другой периферийной информацией, а может состоять даже из нескольких строк другой таблицы. Если вы блокируете страницы вместо строк, все данные в этих страницах будут блокированы точно также как и в индивидуальных строках, согласно уровням изоляции описаным выше.
Основным преимуществом такого подхода является эффективность. Когда SQL не следит за блокированность и разблокированностью строк индивиду-ально, он работает быстрее. С другой стороны, язык SQL был разработан так чтобы максимизировать свои возможности, и произвольно блокирует строки которые необязательно было блокировать.</p>
<p>Похожая возможность, доступная в некоторых системах - это блокировка областей DBS. Области базы данных имеют тенденцию быть больше чем страница, так что этот подход удовлетворяет и достоинству увиличения производительности и недостатку блокирования страниц.
Вообще то лучше отключать блокировку низкого уровня если вам кажется что появились значительные проблемы с эффективностью.</p>
<h3 id="резюме-17">РЕЗЮМЕ</h3>
<p>Ключевые определения, с которыми вы познакомились в этой главе:</p>
<ul>
<li>Синонимы, или как создавать новые имена для объектов данных.</li>
<li>Области базы даных (DBS), или как распределяется доступная память в базе данных.</li>
<li>Транзакция, или как сохранять или восстанавливать изменения в базе данных.</li>
<li>Управление Параллелизмом, или как SQL предохраняет от конфликта одной команды с другой.</li>
</ul>
<p>Синонимы - это объекты, в том смысле, что они имеют имена и (иногда) владельцев, но естественно они не могут существовать без таблицы, чье имя они замещают. Они могут быть общими и следовательно доступными каждому кто имеет доступ к объекту, или они могут принадлежать определенному пользователю.
Области DBS или просто DBS - это подразделы базы данных, которые распределены для пользователей. Связанные таблицы, (например таблицы, которые будут часто объединяться,) лучше хранить в общей для них DBS.
СOMMIT и ROLLBACK - это команды, используемые для выполнения изменений в базе данных, в то время когда предыдущая команда COMMIT или команда ROLLBACK, начинают сеанс и оставляют изменения, или игнорируют их как группу.
Средство Управление Параллелизмом - определяет в какой степени одновременно поданные команды будут мешать друг другу. Оно является адаптируемым средством, находящим компромис между производительностью базы данных и изоляцией действующих команд.</p>
<h3 id="работа-с-sql-13">РАБОТА С SQL</h3>
<ul>
<li>Создайте область базы данных с именем Myspace которая выделяет 15 процентов своей области для индексов, и 40 процентов на расширение строк.</li>
<li>Вы получили право SELECT в таблице Порядков продавца Diane. Введите команду так чтобы вы могли ссылаться к этой таблице как к &quot;Orders&quot; не используя имя &quot;Diane&quot; в качестве префикса.</li>
<li>Если произойдет сбой питания, что случится с всеми изменениями сделанными во время текущей транзакции?</li>
<li>Если вы не можете видеть строку из-за ее блокировки, какой это тип блокировки?</li>
<li>Если вы хотите получить общее, максимальное, и усредненое значения сумм приобретений для всех порядков, и не хотите при этом запрещать другим пользоваться таблицей, какой уровень изоляции будет этому соответствовать?</li>
</ul>
<h2 id="глава-24-как-данные-sql-содержатся-в-упорядоченном-виде">Глава 24. КАК ДАННЫЕ SQL СОДЕРЖАТСЯ В УПОРЯДОЧЕННОМ ВИДЕ</h2>
<p>В ЭТОЙ ГЛАВЕ, ВЫ УЗНАЕТЕ КАК ТИПОВАЯ SQL БАЗА данных сохраняет самоорганизованность. Не удивительно, что самоорганизованность обеспечива ется реляционной базой данных, создаваемой и поддерживаемой с помощью программы. Вы можете обращаться к этим таблицам самостоятельно для по лучения информации о привилегиях, таблицах, индексах, и так далее. Эта глава покажет вам некоторые типы содержащиеся в такой базе данных.</p>
<h3 id="каталог-системы">КАТАЛОГ СИСТЕМЫ</h3>
<p>Чтобы функционировать как SQL база данных, ваша компьютерная система должна следить за многими различными вещями: таблицами, представлениями, индексами, синонимами, привилегиями, пользователями, и так далее.
Имеются различные способы делать это, но ясно, что наиболее логичный, эффективный, и согласованный способ делать это в реляционной среде состоит в том, чтобы сохранять эту информацию в таблицах. Это дает возможность компьютеру размещать и управлять информацией в которой он нуждается, используя те же самые процедуры которые он использует чтобы размещать и управлять данными которые он хранит для вас. Хотя это - вопрос конкретной программы, а не часть стандарта ANSI, большинство SQL баз данных, используют набор SQL таблиц хранящих служебную информацию для своих внутренних потребностей. Этот набор называется в различных публикациях как - системный каталог, словарь данных, или просто системные таблицы (Термин &quot;словарь данных&quot; может также относится к общему архиву данных, включая информацию о физических параметрах базы данных которые хранятся вне SQL. Следовательно, имеются программы баз данных, которые имеют и системный каталог и словарь данных. )
Таблицы системного каталога - напоминают обычные SQL таблицы: те же строки и столбцы данных. Например, одна таблица каталога обычно содержит информацию о таблицах существующих в базе данных, по одной строке на каждую таблицу базы данных; другая содержит информацию о различных столбцах таблиц, по одной строке на столбец, и так далее. Таблицы каталога создаются и присваиваются с помощью самой базы данных, и идентифицируются с помощью специальных имен, таких например как SYSTEM.
База данных создает эти таблицы и модифицирует их автоматически; таблицы каталога не могут быть непосредственно подвергнуты действию команды модификации.
Если это случится, это значительно запутает всю систему и сделает ее неработоспособной. Однако, в большинстве систем, каталог может быть запрошен пользователем. Это очень полезно, потому что это дает вам возможность узнать кое-что о базе данных, которую вы используете. Конечно, вся информация не всегда доступна всем пользователям. Подобно другим таблицам, доступ к каталогу ограничен для пользователей без соответствующих привилегий. Так как каталог принадлежит самой системе, имеется некоторая неясность относительно того, кто имеет привилегии и кто может предоставить привилегии в этом каталоге. Обычно, привилегии каталога предоставляет суперпользователь, например, администратор системы, зарегистрированый как SYSTEM или DBA. Кроме того, некоторые привилегии могут предоставляться пользователям автоматически.</p>
<h3 id="типичный-системный-каталог">ТИПИЧНЫЙ СИСТЕМНЫЙ КАТАЛОГ</h3>
<p>Давайте рассмотрим некоторые таблицы которые мы могли бы найти в типовом каталоге системы:</p>
<table>
<thead>
<tr>
<th>Таблицы</th>
<th>Содержание</th>
</tr>
</thead>
<tbody>
<tr>
<td>SYSTEMCATALOG</td>
<td>Таблицы (базовые и представления)</td>
</tr>
<tr>
<td>SYSTEMCOLUMNS</td>
<td>Столбцы таблицы</td>
</tr>
<tr>
<td>SYSTEMTABLES</td>
<td>Каталог Представления в SYSTEMCATALOG</td>
</tr>
<tr>
<td>SYSTEMINDEXES</td>
<td>Индексы в таблице</td>
</tr>
<tr>
<td>SYSTEMUSERAUTH</td>
<td>Пользователи базы данных</td>
</tr>
<tr>
<td>SYSTEMTABAUTH</td>
<td>Объектные привилегии пользователей</td>
</tr>
<tr>
<td>SYSTEMCOLAUTH</td>
<td>Столбцовые привилегии пользователей</td>
</tr>
<tr>
<td>SYSTEMSYNONS</td>
<td>Синонимы для таблиц</td>
</tr>
</tbody>
</table>
<p>Теперь, если наш DBA предоставит пользователю Stephen право просматривать SYSTEMCATALOG такой командой,</p>
<pre><code>GRANT SELECT ON SYSTEMCATALOG TO Stephen;
</code></pre>
<p>то Stephen сможет увидеть некоторую информацию обо всех таблицах в базе данных (мы имеем здесь пользователя DBA, пользователя Chris, владельца трех наших типовых таблиц, а также Adrian владельца представления Londoncust ).</p>
<pre><code>SELECT tname, owner, numcolumns, type, CO
FROM SYSTEMCATALOG;
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT tname, owner, numcolumns, type, CO
FROM SYSTEMCATALOG;
</code></pre>
<table>
<thead>
<tr>
<th>   tname</th>
<th>   owner</th>
<th>   numcolumns</th>
<th>   type</th>
<th>    CO</th>
</tr>
</thead>
<tbody>
<tr>
<td>   SYSTEMCATALOG<br style="margin: 0px; padding: 0px;"></td>
<td>   SYSTEM<br style="margin: 0px; padding: 0px;"></td>
<td>   4<br style="margin: 0px; padding: 0px;"></td>
<td>   B<br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   Chris<br style="margin: 0px; padding: 0px;"></td>
<td>   4<br style="margin: 0px; padding: 0px;"></td>
<td>   B<br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   Chris<br style="margin: 0px; padding: 0px;"></td>
<td>   5<br style="margin: 0px; padding: 0px;"></td>
<td>   B<br style="margin: 0px; padding: 0px;"></td>
<td>   Y<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Londoncust<br style="margin: 0px; padding: 0px;"></td>
<td>   Adrian<br style="margin: 0px; padding: 0px;"></td>
<td>   5<br style="margin: 0px; padding: 0px;"></td>
<td>   V<br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Orders<br style="margin: 0px; padding: 0px;"></td>
<td>   Chris<br style="margin: 0px; padding: 0px;"></td>
<td>   5<br style="margin: 0px; padding: 0px;"></td>
<td>   B<br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"> <br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24.1: Содержание таблицы SYSTEMCATALOG
Как вы можете видеть, каждая строка описывает свою таблицу. Первый столбец - имя; второй - имя пользователя который владеет ею; третий - число столбцов которые содержит таблица; и четвертый - код из одного символа, это или B (для базовой таблицы ) или V (для представления). Последний столбец имеет пустые(NULL) значения, если его тип не равен V; и этот столбец указывает, определена или нет возможность проверки. Обратите внимание что SYSTEMCATALOG(СЧИСТЕМНЫЙ КАТАЛОГ) представлен как одна из таблиц в вышеуказаном списке. Для простоты, мы исключили остальные каталоги системы из вывода. Таблицы системного каталога обычно показываются в SYSTEMCATALOG.</p>
<h3 id="использование-представлений-в-таблицах-каталога">ИСПОЛЬЗОВАНИЕ ПРЕДСТАВЛЕНИЙ В ТАБЛИЦАХ КАТАЛОГА</h3>
<p>Поскольку SYSTEMCATALOG - это таблица, вы можете использовать ее в представлении. Фактически можно считать, что имеется такое представление с именем SYSTEMTABLES. Это представление SYSTEMCATALOG содержит только те таблицы, которые входят в системный каталог; это обычно таблицы базы данных, типа таблицы Продавцов, которые показаны в SYSTEMCATALOG, но не в SYSTEMTABLES. Давайте предположим, что только таблицы каталога являются собственностью пользователя SYSTEM. Если вы захотите, вы можете определить другое представление, которое бы специально исключало таблицы каталога из вывода:</p>
<pre><code>CREATE VIEW Datatables
AS SELECT *
FROM SYSTEMCATALOG
WHERE owner &lt; &gt; 'SYSTEM';
</code></pre>
<p>РАЗРЕШИТЬ ПОЛЬЗОВАТЕЛЯМ ВИДЕТЬ (ТОЛЬКО) ИХ СОБСТВЕННЫЕ ОБЪЕКТЫ
Кроме того, имеются другое использование представлений каталога.
Предположим вам нужно чтобы каждый пользователь был способен сделать запрос каталога, для получения информации только из таблиц которыми он владеет. Пока значение USER, в команде SQL постоянно для ID доступа пользователя выдающего команду, оно может всегда быть использоваться, чтобы давать доступ пользователям только к их собственным таблицам. Вы можете, для начала создать следующее представление:</p>
<pre><code>CREATE VIEW Owntables
AS SELECT *
FROM SYSTEMCATALOG
WHERE Owner=USER;
</code></pre>
<p>Теперь вы можете предоставить всем пользователям доступ к этому представлению:</p>
<pre><code>GRANT SELECT ON Owntables TO PUBLIC;
</code></pre>
<p>Каждый пользователь теперь, способен выбирать (SELECT) только те строки из SYSTEMCATALOG, владельцем которых он сам является.
ПРЕДСТАВЛЕНИЕ SYSTEMCOLUMNS
Одно небольшое добавление к этому, позволит каждому пользователю просматривать таблицу SYSTEMCOLUMNS для столбцов из его собственных таблиц. Сначала, давайте рассмотрим ту часть таблицы SYSTEMCOLUMNS, которая описывает наши типовые таблицы( другими словами, исключим сам каталог):</p>
<table>
<thead>
<tr>
<th>   tname</th>
<th>   cname</th>
<th>   datatype</th>
<th>   cnumber</th>
<th>   tabowner</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   snum<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   sname<br style="margin: 0px; padding: 0px;"></td>
<td>   char<br style="margin: 0px; padding: 0px;"></td>
<td>   2<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   city<br style="margin: 0px; padding: 0px;"></td>
<td>   char<br style="margin: 0px; padding: 0px;"></td>
<td>   3<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   comm<br style="margin: 0px; padding: 0px;"></td>
<td>   decimal<br style="margin: 0px; padding: 0px;"></td>
<td>   4<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   cnum<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   cname<br style="margin: 0px; padding: 0px;"></td>
<td>   char<br style="margin: 0px; padding: 0px;"></td>
<td>   2<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   city<br style="margin: 0px; padding: 0px;"></td>
<td>   char<br style="margin: 0px; padding: 0px;"></td>
<td>   3<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   rating<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   4<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   snum<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   5<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Orders<br style="margin: 0px; padding: 0px;"></td>
<td>   onum<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Orders<br style="margin: 0px; padding: 0px;"></td>
<td>   odate<br style="margin: 0px; padding: 0px;"></td>
<td>   date<br style="margin: 0px; padding: 0px;"></td>
<td>   2<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Orders<br style="margin: 0px; padding: 0px;"></td>
<td>   amt<br style="margin: 0px; padding: 0px;"></td>
<td>   decimal<br style="margin: 0px; padding: 0px;"></td>
<td>   3<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Orders<br style="margin: 0px; padding: 0px;"></td>
<td>   cnum<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   4<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Orders<br style="margin: 0px; padding: 0px;"></td>
<td>   snum<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   5<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Как вы можете видеть, каждая строка этой таблицы показывает столбец таблицы в базе данных. Все столбцы данной таблицы должны иметь разные имена, также как каждая таблица должна иметь данного пользователя, и наконец все комбинации пользователей, таблиц, и имен столбцов должны различаться между собой.</p>
<p>Следовательно табличные столбцы: tname (имя таблицы ), tabowner (владелец таблицы ), и cname (имя столбца ), вместе составляют первичный ключ этой таблицы. Столбец datatype( тип данных ) говорит сам за себя. Столбец cnumber (номер столбца ) указывает на местоположении этого столбца внутри таблицы. Для упрощения, мы опустили параметры длины столбца, точности, и масштаба.
Для справки, показана строка из SYSTFMCATALOG которая ссылается к этой таблице:</p>
<table>
<thead>
<tr>
<th>   tname</th>
<th>   owner</th>
<th>   numcolumns</th>
<th>   type</th>
<th>   CO</th>
</tr>
</thead>
<tbody>
<tr>
<td>   SYSTEMCOLUMNS<br style="margin: 0px; padding: 0px;"></td>
<td>   System<br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"> <br style="margin: 0px; padding: 0px;"></td>
<td>   8<br style="margin: 0px; padding: 0px;"></td>
<td>   B<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Некоторые SQL реализации, будут обеспечивать вас большим количеством данных чем показано в этих столбцах, но показанное являются основой для любый реализаций.
Для иллюстрации процедуры предложенной в начале этого раздела, имеется способ, позволяющий каждому пользователю видеть информацию SYSTEMCOLUMNS только для принадлежащих ему таблиц:</p>
<pre><code>CREATE VIEW Owncolumns
AS SELECT *
FROM SYSTEMCOLUMNS
WHERE tabowner=USER;

GRANT SELECT ON Owncolumns TO PUBLIC;
</code></pre>
<h3 id="комментарий-в-содержании-каталога">КОММЕНТАРИЙ В СОДЕРЖАНИИ КАТАЛОГА</h3>
<p>Большинство версий SQL, позволяют вам помещать комментарии(ремарки) в специальные столбцы пояснений таблиц каталогов SYSTEMCATALOG и SYSTEMCOLUMNS, что удобно, так как эти таблицы не всегда могут объяснить свое содержание. Для простоты, мы пока исключали этот столбец из наших иллюстраций.
Можно использовать команду COMMENT ON со строкой текста, чтобы пояснить любую строку в одной из этих таблиц. Состояние - TABLE, для комментирования в SYSTEMCATALOG, и текст - COLUMN, для SYSTEMCOLUMNS.
Например:</p>
<pre><code>COMMENT ON TABLE Chris.Orders
IS 'Current Customer Orders';
</code></pre>
<p>Текст будет помещен в столбец пояснений SYSTEMCATALOG. Обычно, максимальная длина таких пояснений - 254 символов.
Сам комментарий, указывается для конкретной строки, одна с tname=Orders, а другая owner=Chris. Мы увидим этот комментарий в строке для таблицы Порядков в SYSTEMCATALOG:</p>
<pre><code>SELECT tname, remarks
FROM SYSTEMCATALOG
WHERE tname='Orders'
AND owner='Chris';
</code></pre>
<p>Вывод для этого запроса показывается в Таблица 24.2.
SYSTEMCOLUMNS работает точно так же. Сначала, мы создаем комментарий</p>
<pre><code>COMMENT ON COLUMN Orders.onum
IS 'Order #';
</code></pre>
<p>затем выбираем эту строку из SYSTEMCOLUMNS:</p>
<pre><code>SELECT cnumber, datatype, cname, remarks
FROM SYSTEMCOLUMNS
WHERE tname='Orders'
AND tabowner='Chris'
AND cname=onum;
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 24.3.
Чтобы изменить комментарий, вы можете просто ввести новую команду COMMENT ON для той же строки. Новый комментарий будет записан поверх старого. Если вы хотите удалить комментарий, напишите поверх него пустой комментарий, подобно следующему:</p>
<pre><code>COMMENT ON COLUMN Orders.onum
IS &quot;;
</code></pre>
<p>и этот пустой комментарий затрет предыдущий.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT tname, remarks FROM SYSTEMCATALOG
WHERE tname='Orders' AND owner='Chris'
</code></pre>
<table>
<thead>
<tr>
<th>   tname</th>
<th>   remarks</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Orders<br style="margin: 0px; padding: 0px;"></td>
<td>   Current Customers Orders<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24.2: Коментарий в SYSTEMCATALOG</p>
<pre><code>SQL Execution Log
SELECT cnumber, datatype, cname, remarks
FROM SYSTEMCOLUMNS WHERE tname='Orders' AND tabowner='Chris'
AND cname='onum'
</code></pre>
<table>
<thead>
<tr>
<th>   cnumber</th>
<th>   datatype</th>
<th>   cname</th>
<th>   remarks</th>
</tr>
</thead>
<tbody>
<tr>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
<td>   integer<br style="margin: 0px; padding: 0px;"></td>
<td>   onum<br style="margin: 0px; padding: 0px;"></td>
<td>   Orders #<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24.3: Коментарий в SYSTEMCOLUMNS</p>
<h3 id="остальное-из-каталога">ОСТАЛЬНОЕ ИЗ КАТАЛОГА</h3>
<p>Здесь показаны оставшиеся из ващих системных таблиц определения, с типовым запросом для каждого:</p>
<pre><code>SYSTEMINDEXES - ИНДЕКСАЦИЯ В БАЗЕ ДАННЫХ
</code></pre>
<p>Имена столбцов в таблице SYSTEMINDEXES и их описания - следующие:</p>
<table>
<thead>
<tr>
<th>   СТОЛБЦЫ</th>
<th>   ОПИСАНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   iname<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя индекса (используемого для его исключения )<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   iowner<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя пользователя который создал индекс<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   tname<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя таблицы которая содержит индекс<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   cnumber<br style="margin: 0px; padding: 0px;"></td>
<td>   Номер столбца в таблице<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   tabowner<br style="margin: 0px; padding: 0px;"></td>
<td>   Пользователь который владеет таблицей содержащей индекс<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   numcolumns<br style="margin: 0px; padding: 0px;"></td>
<td>   Число столбцов в индексе<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   cposition<br style="margin: 0px; padding: 0px;"></td>
<td>   Позиция текущего столбца среди набора индексов<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   isunique<br style="margin: 0px; padding: 0px;"></td>
<td>   Уникален ли индекс (Y или N )<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<h3 id="типовой-запрос">ТИПОВОЙ ЗАПРОС</h3>
<p>Индекс считается неуникальным, если он вызывает продавца, в snum столбце таблицы Заказчиков:</p>
<pre><code>SELECT iname, iowner, tname, cnumber, isunique
FROM SYSTEMINDEXES
WHERE iname='salesperson';
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 24.4.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT iname, iowner, tname, cnumber, isunique
FROM SYSTEMINDEXES WHERE iname='salespeople';
</code></pre>
<table>
<thead>
<tr>
<th>   iname</th>
<th>   iowner</th>
<th>   tname</th>
<th>   cnumber</th>
<th>   isunique</th>
</tr>
</thead>
<tbody>
<tr>
<td>   salesperson<br style="margin: 0px; padding: 0px;"></td>
<td>   Stephan<br style="margin: 0px; padding: 0px;"></td>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   5<br style="margin: 0px; padding: 0px;"></td>
<td>   N<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24.4: Строка из таблицы SYSTEMINDEXES</p>
<h3 id="systemuserauth---пользовательские-и-системные-привилегии-в-базе-данных">SYSTEMUSERAUTH - ПОЛЬЗОВАТЕЛЬСКИЕ И СИСТЕМНЫЕ ПРИВИЛЕГИИ В БАЗЕ ДАННЫХ</h3>
<p>Имена столбцов для SYSTEMUSERAUTH и их описание, следующее:</p>
<table>
<thead>
<tr>
<th>   Столбцы</th>
<th>   Описание</th>
</tr>
</thead>
<tbody>
<tr>
<td>   username<br style="margin: 0px; padding: 0px;"></td>
<td>   Идентификатор (ID ) доступа пользователя<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   password<br style="margin: 0px; padding: 0px;"></td>
<td>   Пароль пользователя вводимый при регистрации<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   resource<br style="margin: 0px; padding: 0px;"></td>
<td>   Где пользователь имеет права RESOURCE<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   dba<br style="margin: 0px; padding: 0px;"></td>
<td>   Где пользователь имеет права DBA<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Мы будем использовать простую схему системных привилегий, которая представлена в Главе 22, где были представлены три системных привилегии - CONNECT( ПОДКЛЮЧИТЬ ), RESOURCE( РЕСУРСЫ ) и DBA. Все пользователи получают CONNECT по умолчанию при регистрации, поэтому он не описан в таблице выше. Возможные состояния столбцов resource и dba могут быть - Y (Да, пользователь имеет привилегии) или - No (Нет, пользователь не имеет привилегий).
Пароли (password) доступны только высоко привилегированным пользователям, если они существуют. Следовательно запрос этой таблицы можно вообще делать только для информации относительно привилегий системы и пользователей.
ТИПОВОЙ ЗАПРОС Чтобы найти всех пользователей которые имеют привилегию RESOURCE, и увидеть какие из них - DBA, вы можете ввести следующее условие:</p>
<pre><code>SELECT username, dba
FROM SYSTEMUSERAUTH
WHERE resource='Y';
</code></pre>
<p>Вывод для этого запроса показывается в Таблице 24.5.</p>
<h3 id="systemtabauth---привилегии-объекта-оторые-не-определяют-столбцы">SYSTEMTABAUTH - ПРИВИЛЕГИИ ОБЪЕКТА ОТОРЫЕ НЕ ОПРЕДЕЛЯЮТ СТОЛБЦЫ</h3>
<p>Здесь показаны имена столбцов в таблице SYSTEMTABAUTH и их описание:</p>
<table>
<thead>
<tr>
<th>   COLUMN</th>
<th>   ОПИСАНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>username Пользователь который имеет привилегии grantor Пользователь который передает привилегии по имени пользователя tname Имя таблицы в которой существуют привилегии owner Владелец tname selauth Имеет ли пользователь привилегию SELECT insauth Имеет ли пользователь привилегию INSERT delauth Имеет ли пользователь привилегию DELETE
Возможные значения для каждой из перечисленных привилегий объекта (имена столбцов которых окончиваются на auth ) - Y, N, и G. G указывает что пользователь имеет привилегию с возможностью передачи привилегий.
В каждой строке, по крайней мере один из этих столбцов должен иметь состояние отличное от N (другими словами, иметь хоть какую-то привилегию).</p>
<p>SQL Execution Log</p>
<pre><code>SELECT username, dba FROM SYSTEMUSERAUTH
   WHERE resource='Y' ;
</code></pre>
<table>
<thead>
<tr>
<th>   username</th>
<th>   dba</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
<td>   N<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Adrian<br style="margin: 0px; padding: 0px;"></td>
<td>   Y<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24 .5: Пользователи которые имеют привилегию RESOURCE
Первые четыре столбца этой таблицы составляют первичный ключ. Это означает что каждая комбинация из tname, владелец-пользователь (не забудьте, что две различные таблицы с различными владельцами могут иметь одно и тоже имя ), пользователь и пользователь передающий права(гарантор ), должна быть уникальной. Каждая строка этой таблицы содержит все привилегии (которые не являются определенным столбцом ), предоставляются одним определенным пользователем другому определенному пользователю в конкретном объекте. UPDATE и REFERENCES, являются привилегиями, которые могут быть определенными столбцами, и находиться в различных таблицах каталога. Если пользователь получает привилегии в таблице от более чем одного пользователя, такие привилегии могут быть отдельными строками созданными в этой таблице. Это необходимо для каскадного отслеживания при вызове привилегий.
ТИПОВОЙ ЗАПРОС. Чтобы найти все привелегии SELECT, INSERT, и DELETE, которые Adrian предоставляет пользователям в таблице Заказчиков, вы можете ввести следующее (вывод показан в Таблице 24.6 ):</p>
<pre><code>SELECT username, selauth, insauth, delauth
FROM SYSTEMTABAUTH
WHERE grantor='Adrian'
ANDtname='Customers';
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT username, selauth, insauth, delauth
FROM SYSTEMTABAUTH WHERE grantor='Adrian'
AND tname='Customers';
</code></pre>
<table>
<thead>
<tr>
<th>   username</th>
<th>   selauth</th>
<th>   insauth</th>
<th>   delauth</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Claire<br style="margin: 0px; padding: 0px;"></td>
<td>   G<br style="margin: 0px; padding: 0px;"></td>
<td>   Y<br style="margin: 0px; padding: 0px;"></td>
<td>   N<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Norman<br style="margin: 0px; padding: 0px;"></td>
<td>   Y<br style="margin: 0px; padding: 0px;"></td>
<td>   Y<br style="margin: 0px; padding: 0px;"></td>
<td>   Y<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24. 6: Пользователи получившие привилегии от Adrian</p>
<p>Выше показано, что Adrian предоставил Claire привилегии INSERT и SELECT в таблице Заказчиков, позднее предоставив ей права на передачу привилегий. Пользователю Norman, он предоставил привелегии SELECT, INSERT, и DELETE, но не дал возможность передачи привилегий ни в одной из них. Если Claire имела привилегию DELETE в таблице Заказчиков от какого-то другого источника, в этом запросе это показано не будет.</p>
<h3 id="systemcolauth">SYSTEMCOLAUTH</h3>
<table>
<thead>
<tr>
<th>   СТОЛБЦЫ</th>
<th>   ОПИСАНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td> <br style="margin: 0px; padding: 0px;"></td>
<td> <br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>username Пользователь который имеет привилегии grantor Пользователь который предоставляет привилегии другому пользователю tname Имя таблицы в которой существуют привилегии cname Имя столбца в котором существуют привилегии owner Владелец tname updauth Имеет ли пользователь привилегию UPDATE в этом столбце refauth Имеет ли пользователь привилегию REFERENCES в этом столбце
Столбцы updauth и refauth могут быть в состоянии Y, N, или G; но не могут быть одновременно в состоянии N для одной и той же строки. Это - первые пять столбцов таблицы, которы не составляют первичный ключ. Он отличается от первичного ключа SYSTEMTABAUTH в котором содержится поле cname, указывающее на определенный столбец обсуждаемой таблицы для которой применяются одна или обе привилегии. Отдельная строка в этой таблице может существовать для каждого столбца в любой данной таблицы в которой одному пользователю передаются превилегии определенного столбца с помощью другого пользователя. Как и в случае с SYSTEMTABAUTH та же привилегия может быть описана в более чем одной строке этой таблицы если она была передана более чем одним пользователем.
ТИПОВОЙ ЗАПРОС. Чтобы выяснить, в каких столбцах какой таблицы вы имеете привилегию REFERENCES, вы можете ввести следующий запрос (вывод показывается в Таблице 24.7 )</p>
<pre><code>SELECT owner, tname, cname
FROM SYSTEMCOLAUTH
WHERE refauth IN ('Y', 'G')
 AND username=USER
ORDER BY 1, 2;
</code></pre>
<p>который показывает, что эти две таблицы, которые имеют различных владельцев, но одинаковые имя, в действительности, совершенно разные таблицы (т.е. это не как два синонима для одной таблицы ).</p>
<p>SQL Execution Log</p>
<pre><code>SELECT OWNER, TNAME, CNAME FROM SYSTEMCOLAUTH
WHERE refaulth IN ('Y', 'G' ) AND username=USER
ORDER BY 1, 2;
</code></pre>
<table>
<thead>
<tr>
<th>   owner</th>
<th>   tname</th>
<th>   cname</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   cnum<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   sname<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   sname<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Gillan<br style="margin: 0px; padding: 0px;"></td>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   cnum<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24. 7: Столбцы в пользователь имеет привилегию INSERT</p>
<h3 id="systemsynons---синонимы-для-таблиц-в-базе-данных">SYSTEMSYNONS - СИНОНИМЫ ДЛЯ ТАБЛИЦ В БАЗЕ ДАННЫХ</h3>
<p>Это - имена столбцов в таблице SYSTEMSYNONS и их описание:</p>
<table>
<thead>
<tr>
<th>   СТОЛБЕЦ</th>
<th>   ОПИСАНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>   synonym<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя синонима<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   synowner<br style="margin: 0px; padding: 0px;"></td>
<td>   Пользователь, который является владельцем синонима (может быть PUBLIC (ОБЩИЙ))<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   tname<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя таблицы используемой владельцем<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   tabowner<br style="margin: 0px; padding: 0px;"></td>
<td>   Имя пользователя который является владельцем таблицы<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<h3 id="типовой-запрос-1">ТИПОВОЙ ЗАПРОС.</h3>
<p>Предположим, что Adrian имеет синоним Clients для таблицы Заказчиков принадлежащей Diane, и что имеется общий синоним Customers для этой же таблицы. Вы делаете запрос таблицы для всех синонимов в таблице Заказчиков (вывод показывается в Таблице 24.8 ):</p>
<pre><code>SELECT *
FROM SYSTEMSYNONS
WHERE tname='Customers'
</code></pre>
<p>SQL Execution Log</p>
<pre><code>SELECT * FROM SYSTEMSYNONS
WHERE tname='Customers';
</code></pre>
<table>
<thead>
<tr>
<th>   synonym</th>
<th>   synowner</th>
<th>   tname</th>
<th>   tabowner</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Clients<br style="margin: 0px; padding: 0px;"></td>
<td>   Adrian<br style="margin: 0px; padding: 0px;"></td>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   PUBLIC<br style="margin: 0px; padding: 0px;"></td>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   Diane<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24.8: Синонимы для таблицы Заказчиков</p>
<h3 id="другое-использование-каталога">ДРУГОЕ ИСПОЛЬЗОВАНИЕ КАТАЛОГА</h3>
<p>Конечно, вы можете выполнять более сложные запросы в системном каталоге. Обьединения, например, могут быть очень удобны. Эта команда позволит вам увидеть столбцы таблиц и базовые индексы установленые для каждого, (вывод показывается в Таблице 24.9 ):</p>
<pre><code>SELECT a.tname, a.cname, iname, cposition
FROM SYSTEMCOLUMNS a, SYSTEMINDEXES b
WHERE a.tabowner=b. tabowner
AND a.tname=b.tname
AND a.cnumber=b.cnumber
ORDER BY 3 DESC, 2;
</code></pre>
<p>Она показывает два индекса, один для таблицы Заказчиков и один для таблицы Продавцов. Последний из них - это одностолбцовый индекс с именем salesno в поле snum; он был помещен первым из-за сортировки по убыванию (в обратном алфавитном порядке ) в столбце iname. Другой индекс, custsale, используется продавцами чтобы отыскивать своих заказчиков. Он основывается на комбинации полей snum и cnum внутри таблицы Заказчиков, с полем snum приходящим в индексе первым, как это и показано с помощью поля cposition.</p>
<p>SQL Execution Log</p>
<pre><code>SELECT a.tname, a.cname, iname, cposition
FROM SYSTEMCOLUMNS a, SYSTEMINDEXES b
WHERE a.tabowner=b.tabowner
AND a.tname=b.tname
AND a.cnumber=b.cnumber
ORDER BY 3 DESC, 2;
</code></pre>
<table>
<thead>
<tr>
<th>   tname</th>
<th>   cname</th>
<th>   iname</th>
<th>   cposition</th>
</tr>
</thead>
<tbody>
<tr>
<td>   Salespeople<br style="margin: 0px; padding: 0px;"></td>
<td>   sname<br style="margin: 0px; padding: 0px;"></td>
<td>   salesno<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   cnum<br style="margin: 0px; padding: 0px;"></td>
<td>   custsale<br style="margin: 0px; padding: 0px;"></td>
<td>   2<br style="margin: 0px; padding: 0px;"></td>
</tr>
<tr>
<td>   Customers<br style="margin: 0px; padding: 0px;"></td>
<td>   snum<br style="margin: 0px; padding: 0px;"></td>
<td>   custsale<br style="margin: 0px; padding: 0px;"></td>
<td>   1<br style="margin: 0px; padding: 0px;"></td>
</tr>
</tbody>
</table>
<p>Таблица 24.9 Столбцы и их индексы</p>
<p>Подзапросы также могут быть использованы. Имеется способ увидеть данные столбца только для столбцов из таблиц каталога:</p>
<pre><code>SELECT *
FROM SYSTEMCOLUMNS
WHERE tname IN
( SELECT tname
FROM SYSTEMCATALOG);
</code></pre>
<p>Для простоты, мы не будем показывать вывод этой команды, которая состоит из одного входа для каждого столбца каждой таблицы каталога.
Вы могли бы поместить этот запрос в представление, назвав его, например, SYSTEMTABCOLS, для представления SYSTEMTABLES.</p>
<h3 id="резюме-18">РЕЗЮМЕ</h3>
<p>Итак, система SQL использует набор таблиц, называемый ситемным каталогом в структуре базы данных. Эти таблицы могут запрашиваться но модифицироваться. Кроме того, вы можете добавлять комментарии столбцов в (и удалять их из) таблицы SYSTEMCATALOG и SYSTEMCOLUMNS.
Создание представлений в этих таблицах - превосходный способ точно определить, какая пользовательская информация может быть доступной.
Теперь, когда вы узнали о каталоге, вы завершили ваше обучение SQL в диалоговом режиме. Следующая глава этой книги расскажет вам как SQL используется в программах которые написаны прежде всего на других языках но которые способны извлечь пользу из возможностей SQL, взаимодействуя с его таблицами базы данных.</p>
<h3 id="работа-с-sql-14">РАБОТА С SQL</h3>
<ul>
<li>Сделайте запрос каталога чтобы вывести, для каждой таблицы имеющей более чем четыре столбца, имя таблицы, имя владелеца, а также имя столбцов и тип данных этих столбцов.</li>
<li>Сделайте запрос каталога чтобы выяснить, сколько синонимов существует для каждой таблицы в базе данных. Не забудьте, что один и тот же синоним принадлежащий двум различным пользователям - это фактически два разных синонима.</li>
<li>Выясните сколько таблиц имеют индексы в более чем пятьдесяти процентов их столбцов.</li>
</ul>
<h2 id="глава-25-использование-sql-с-другим-языком">Глава 25. ИСПОЛЬЗОВАНИЕ SQL С ДРУГИМ ЯЗЫКОМ</h2>
<p>( ВЛОЖЕННЫЙ SQL )</p>
<p>В ЭТОЙ ГЛАВЕ ВЫ УЗНАЕТЕ КАК SQL ИСПОЛЬЗУЕТСЯ для расширения программ написанных на других языках. Хотя непроцедурность языка SQL делает его очень мощным, в то же время это накладывает на него большое число ограничений. Чтобы преодолеть эти ограничения, вы можете включать SQL в программы написанные на том или другом процедурном языке( имеющем определенный алгоритм). Для наших примеров, мы выбрали Паскаль, считая что этот язык наиболее прост в понимании для начинающих, и еще потому, что Паскаль - один из языков для которых ANSI имеет полуофициальный стандарт.</p>
<h3 id="что-такое---вложение-sql">ЧТО ТАКОЕ - ВЛОЖЕНИЕ SQL</h3>
<p>Чтобы вложить SQL в другой язык, вы должны использовать пакет программ который бы обеспечивал поддержку вложения SQL в этот язык и конечно же, поддержку самого языка. Естественно, вы должны быть знакомы с языком который вы используете. Главным образом, вы будете использовать команды SQL для работы в таблицах базы данных, передачи результатов вывода в программу и получение ввода из программы в которую они вкладываются, обобщенно ссылаясь к главной программе (которая может или не может ппринимать их из диалога или посылать обратно в диалог пользователя и программы).</p>
<h3 id="зачем-вкладывать-sql">ЗАЧЕМ ВКЛАДЫВАТЬ SQL?</h3>
<p>Хотя и мы потратили некоторое время на то чтобы показать что умеет делать SQL, но если вы - опытный программист, вы вероятно отметили, что сам по себе, он не очень полезен при написании программ. Самое очевидное ограничение - это то, что в то время как SQL может сразу выполнить пакет команды, интерактивный SQL в основном выполняет по одной команде в каждый момент времени. Типы логических конструкций типа</p>
<pre><code>if ... then (&quot;если ... то&quot; ),
for ... do (&quot;для ... выполнить&quot;) и
while ... repeat( &quot;пока ... повторять&quot; ) -
</code></pre>
<p>используемых для структур большинства компьютерных программ, здесь отсутствуют, так что вы не сможете принять решение - выполнять ли, как выполнять, или как долго выполнять одно действие в результате другого действия. Кроме того, интерактивный SQL не может делать многого со значениями, кроме ввода их в таблицу, размещения или распределения их с помощью запросов, и конечно вывода их на какое-то устройство.
Более традиционные языки, однако, сильны именно в этих областях. Они разработаны так чтобы программист мог начинать обработку данных, и основываясь на ее результатах, решать, делать ли это действие или другое, или же повторять действие до тех пока не встретится некоторое условие, создавая логические маршруты и циклы. Значения сохраняются в переменных, которые могут использоваться и изменяться с помощью любого числа команд. Это дает вам возможность указывать пользователям на ввод или вывод этих команд из файла, и возможность форматировать вывод сложными способами (например, преобразовывать числовых данных в диаграммы). Цель вложенного SQL состоит в том, чтобы объединить эти возможности, позволяющие вам создавать сложные процедурные программы которые адресуют базу данных посредством SQL - позволяя вам устранить сложные действия в таблицах на процедурном языке который не ориентирован на такую структуру данных, в тоже время поддерживая структурную строгость процедурного языка.</p>
<h3 id="как-делаются-вложения-sql">КАК ДЕЛАЮТСЯ ВЛОЖЕНИЯ SQL.</h3>
<p>Команды SQL помещаются в исходный текст главной программы, которой предшествует фраза - EXEC SQL (EXECute SQL). Далее устанавливаются некоторые команды которые являются специальными для вложенной формы SQL, и которые будут представлены в этой главе.
Строго говоря, стандарт ANSI не поддерживает вложенный SQL как таковой. Он поддерживает понятие, называемое - модуль, который более точно, является вызываемым набором процедур SQL, а не вложением в другой язык. Официальное определение синтаксиса вложения SQL, будет включать расширение официального синтаксиса каждого языка в который может вкладываться SQL, что весьма долгая и неблагодарная задача, которую ANSI избегает. Однако, ANSI обеспечивает четыре приложения (не являющиеся частью стандарта ), которые определяют синтаксис вложения SQL для четырех языков: КОБОЛ, ПАСКАЛЬ, ФОРТРАН, и ПЛ/1. Язык C - также широко поддерживается как и другие языки. Когда вы вставляете команды SQL в текст программы написанной на другом языке, вы должны выполнить предкомпиляцию прежде, чем вы окончательно ее скомпилируете.
Программа называемая прекомпилятором (или препроцессором ), будет просматривать текст вашей программы и преобразовывать команды SQL, в форму удобную для использования базовым языком.
Затем вы используете обычный транслятор чтобы преобразовывать программу из исходного текста в выполняемый код.
Согласно подходу к модульному языку определенному ANSI, основная программа вызывает процедуры SQL. Процедуры выбирают параметры из главной программы, и возвращают уже обработанные значения, обратно в основную программу. Модуль может содержать любое число процедур, каждая из которых состоит из одиночной команды SQL. Идея в том, чтобы процедуры могли работать тем же самым способом чтго и процедуры на языке в который они были вложены( хотя модуль еще должен идентифицировать базовый язык из-за различий в типах данных различных языков ).
Реализации могут удовлетворить стандарту, выполнив вложение SQL таким способом, как если бы модули уже были точно определены. Для этой цели прекомпилятор будет создавать модуль, называемый модулем доступа.
Только один модуль, содержащий любое число процедур SQL, может существовать для данной программы. Размещение операторов SQL непосредственно в главном коде, происходит более просто и более практично чем непосредственно создание самих модулей.
Каждая из программ использующих вложение SQL, связана с ID доступа, во время ее выполнения. ID доступа, связанный с программой, должен иметь все привилегии чтобы выполнять операции SQL, выполняемые в программе. Вообще то, вложенная программа SQL регистрируется в базе данных, также как и пользователь, выполняющий программу. Более подробно, это определяет проектировщик, но вероятно было бы неплохо для включить в вашу программу команду CONNECT или ей подобную.</p>
<h3 id="использование-переменных-основного-языка-в-sql">ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННЫХ ОСНОВНОГО ЯЗЫКА В SQL</h3>
<p>Основной способ которым SQL и части базового языка ваших программ будут связываться друг с другом - это с помощью значений переменных. Естественно, что разные языки распознают различные типы данных для переменных. ANSI определяет эквиваленты SQL для четыре базовых языков - ПЛ/1, Паскаль, КОБОЛ, и ФОРТРАН; все это подробности описаны в Приложении B. Эквиваленты для других языков - определяет проектировщик.</p>
<p>Имейте в виду, что типы, такие как DATE, не распознаются ANSI; и следовательно никаких эквивалентных типов данных для базовых языков, не существуют в стандарте ANSI. Более сложные типы данных базового языка, такие как матрицы, не имеют эквивалентов в SQL. Вы можете использовать переменные из главной программы во вложенных операторах SQL везде, где вы будете использовать выражения значений. (SQL, используемый в этой главе, будет пониматься как к вложенный SQL, до тех пор пока это не будет оговорено особо. )
Текущим значением переменной, может быть значение, используемое в команде. Главные переменные должны -</p>
<ul>
<li>быть обьявленными в SQL DECLARE SESSION (РАЗДЕЛ ОБЪЯВЛЕНИЙ ) который будет описан далее.</li>
<li>иметь совместимый тип данных с их функциями в команде SQL (например, числовой тип если они вставляется в числовое поле )</li>
<li>быть назначеными значению во время их использования в команде SQL, если команда SQL самостоятельно не может сделать назначение.</li>
<li>предшествовать двоеточию (:) когда они упоминаются в команде SQL.</li>
</ul>
<p>Так как главные переменные отличаются от имен столбцов SQL наличием у них двоеточия, вы можете использовать переменные с теми же самыми именами что и ваши столбцы, если это конечно нужно. Предположим что вы имеете четыре переменных в вашей программе, с именами: id_num, salesperson, loc, и comm. Они содержат значения которые вы хотите вставить в таблицу Продавцов. Вы могли бы вложить следующую команду SQL в вашу программу:</p>
<pre><code>EXEC SQL INSERT INTO Salespeople
VALUES (:id_num, :salesperson, :loc, :comm)
</code></pre>
<p>Текущие значения этих переменных будут помещены в таблицу. Как вы можете видеть, переменная comm имеет то же самое имя что и столбец в который это значение вкладывается. Обратите внимание, что точка с запятой в конце команды отсутствует. Это потому, что соответствующее завершение для вложенной команды SQL зависит от языка для которого делается вложение. Для Паскаля и PL/1, это будет точка с запятой; для КОБОЛА, слово END-EXEC ; и для ФОРТРАНА не будет никакого завершения. В других языках это зависит от реализации, и поэтому мы договоримся что будем использовать точку с запятой (в этой книге) всегда, чтобы не
противоречить интерактивному SQL и Паскалю. Паскаль завершает вложенный SQL и собственные команды одинаково - точкой с запятой. Способ сделать команду полностью такой как описана выше, состоит в том, чтобы включать ее в цикл и повторять ее, с различными значениями переменных, как например показано в следующем примере:</p>
<pre><code>while not end-ot-file (input) do
begin
readln (id_num, salesperson, loc, comm);
EXEC SOL INSERT INTO Salespeople
VALUES (:id_num, :salesperson, :loc, :comm);
end;
</code></pre>
<p>Фрагмент программы на ПАСКАЛЕ, определяет цикл, который будет считывать значения из файла, сохранять их в четырех проименованных переменных, сохранять значения этих переменных в таблице Продавцов, и затем считывать следующие четыре значения, повторяя этот процесс до тех пор пока весь входной файл не прочитается. Считается, что каждый набор значений завершается возвратом каретки (для незнакомых с Паскалем, функция readln считывает вводимую информацию и переходит на следующую строку источника этой информации). Это дает вам простойспособ передать данные из текстового файла в реляционную структуру.
Конечно, вы можете сначала обработать данные любыми возможными способами на вашем главном языке, например для исключения всех комиссионных ниже значения .12</p>
<pre><code>while not end-ot-file (input) do
begin
readln (id_num, salesperson, loc, comm);
if comm &gt;=.12 then
EXEC SQL INSERT INTO Salespeople
VALUES (:id_num, :salesperson, :loc, :comm);
end;
</code></pre>
<p>Только строки которые встретят условие comm &gt;=.12 будут вставлены в вывод. Это показывает что можно использовать и циклы и условия как нормальные для главного языка.</p>
<h3 id="объявление-переменных">ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ</h3>
<p>Все переменные на которые имеется ссылка в предложениях SQL, должны сначала быть обьявлены в SQL DECLARE SECTION (РАЗДЕЛе ОБЪЯВЛЕНИЙ ), использующем обычный синтаксис главного языка. Вы можете иметь любое число таких разделов в программе, и они могут размещаться где-нибудь в коде перед используемой переменной, подчиненной ограничениям определенным в соответствии с главным языком. Раздел объявлений должен начинать и кончаться вложенными командами SQL - BEGIN DECLARE SECTION (Начало Раздела Объявлений ) и END DECLARE SECTION (Конец Раздела Объявлений ), которым предшествует, как обычно EXEC SQL (Выполнить).
Чтобы обьявить переменные используемые в предыдущем примере, вы можете ввести следующее:</p>
<pre><code>EXEC SQL BEGIN DECLARE SECTION;
Var
id-num: integer;
Salesperson: packed array (1 . .10) ot char;
loc: packed array (1. .10) ot char;
comm: real;
EXEC SQL END DECLARE SECTION;
</code></pre>
<p>Для незнакомых с ПАСКАЛем, i - это заголовок который предшествует ряду обьявляемых переменных, и упакованным (или распакованным ) массивам являющимися серией фиксированных переменных значений различаемых
с помощью номеров( например, третий символ loc будет loc (3)). Использование точки с запятой после каждой переменной указывает на то что это - Паскаль, а не SQL.</p>
<h3 id="извлечение-значений-переменных">ИЗВЛЕЧЕНИЕ ЗНАЧЕНИЙ ПЕРЕМЕННЫХ</h3>
<p>Кроме помещения значений переменных в таблицы используя команды SQL, вы можете использовать SQL чтобы получать значения для этих переменных. Один из способов делать это - с помощью разновидности команды SELECT которая содержит предложение INTO. Давайте вернемся к нашему предыдущему примеру и переместим строку Peel из таблицы Продавцов в наши переменные главного языка.</p>
<pre><code>EXEC SQL SELECT snum, sname, city, comm
INTO :id_num, :salesperson, :loc, :comm
FROM Salespeople
WHERE snum=1001;
</code></pre>
<p>Выбранные значения помещаются в переменные с упорядоченными именами указанными в предложении INTO. Разумееется, переменные с именами указанными в предложении INTO должны иметь соответствующий тип чтобы принять эти значения, и должна быть своя переменная для каждого выбранного столбца. Если не учитывать присутствие предложения INTO, то этот запрос - похож на любой другой. Однако, предложение INTO добавляет значительное ограничение к запросу. Запрос должен извлекать не более одной строки. Если он извлекает много строк, все они не могут быть вставлены одновременно в одну и ту же переменную. Команда естественно потерпит неудачу. По этой причине, SELECT INTO должно использоваться только при следующих условиях:</p>
<ul>
<li>когда вы используете предикат проверяющий значения, которое как вы знаете, могут быть уникальным, как в этом примере. Значения которые, как вы знаете, могут быть уникальными - это те значения которые имеют принудительное ограничение уникальности или уникальный индекс, как это говорилось в Главах 17 и 18.</li>
<li>когда вы используете одну или более агрегатных функций и не используете GROUP BY.</li>
<li>когда вы используете SELECT DISTINCT во внешнем ключе с предикатом ссылающимся на единственное значение родительского ключа (обеспечивая вашей системе предписание справочной целостность), как в следующем примере:</li>
</ul>
<pre><code>EXEC SQL SELECT DISTINCT snum
INTO :salesnum
FROM Customers
WHERE snum=
(SELECT snum
FROM Salespeople
WHERE sname='Motika');
</code></pre>
<p>Предпологалось что Salespeople.sname и Salespeople.snum - это соответственно, уникальный и первичный ключи этой таблицы, а Customers.snum - это внешний ключ ссылающийся на Salespeople.snum, и вы предполагали что этот запрос произведет единственную строку. Имеются другие случаи, когда вы можете знаете, что запрос должен произвести единственную строку вывода, но они мало известны и, в большинстве случаев, вы основываетесь на том что ваши данные имеют целостность, которая не может быть предписана с помощью ограничений. Не полагайтесь на это! Вы создаете программу которая, вероятно, будет использоваться в течение некоторого времени, и лучше всего проиграть ее чтобы быть гарантированным в будущем от возможных отказов. Во всяком случае, нет необходимости группировать запросы которые производут одиночные строки, поскольку SELECT INTO - используется только для удобства.
Как вы увидите, вы можете использовать запросы выводящие многочисленные строки, используя курсор.</p>
<h3 id="курсор">КУРСОР</h3>
<p>Одна из сильных качеств SQL - это способность функционировать на всех строках таблицы, чтобы встретить определенное условие как блок запись, не зная сколько таких строк там может быть. Если десять строк удовлетворяют предикату, то запрос может вывести все десять строк. Если десять миллионов строк определены, все десять миллионов строк будут выведены. Это несколько затруднительно, когда вы попробуете связать это с другими языками. Как вы сможете назначать вывод запроса для переменных когда вы не знаете как велик будет вывод ? Решение состоит в том, чтобы использовать то, что называется - курсором. Вы вероятно знакомы с курсором, как с мигающей черточкой, которая отмечает вашу позицию на экране компьютера. Вы можете рассматривать SQL курсор как устройство, которое аналогично этому, отмечает ваше место в выводе запроса, хотя аналогия не полная.
Курсор - это вид переменной, которая связана с запросом. Значением этой переменной может быть каждая строка, которая выводится при запросе. Подобно главным переменным, курсоры должны быть обьявлены прежде, чем они будут использованы. Это делается командой DECLARE CURSOR, следующим образом:</p>
<pre><code>EXEC SQL DECLARE CURSOR Londonsales FOR
SELECT *
FROM Salespeople
WHERE city='London';
</code></pre>
<p>Запрос не выполнится немедленно; он - только определяется. Курсор немного напоминает представление, в котором курсор содержит запрос, а содержание курсора - напоминает любой вывод запроса, каждый раз когда курсор становится открытым. Однако, в отличие от базовых таблиц или представлений, строки курсора упорядочены: имеются первая, вторая...
... и последняя строка курсора. Этот порядок может быть произвольным с явным управлением с помощью предложения ORDER BY в запросе, или же по умолчанию следовать какому-то упорядочению определяемому инструментально-определяемой схемой. Когда вы находите точку в вашей программе в которой вы хотите выполнить запрос, вы открываете курсор с помощью следующей команды:</p>
<pre><code>EXEC SQL OPEN CURSOR Londonsales;
</code></pre>
<p>Значения в курсоре могут быть получены, когда вы выполняете именно эту команду, но не предыдущую команду DECLARE и не последующую команду FETСH. Затем, вы используете команду FETCH чтобы извлечь вывод из этого запроса, по одной строке в каждый момент времени.</p>
<pre><code>EXEC SQL FETCH Londonsales INTO :id_num,
:salesperson, :loc, :comm;
</code></pre>
<p>Это выражение переместит значения из первой выбраной строки, в переменные. Другая команда FETCH выводет следующий набор значений. Идея состоит в том, чтобы поместить команду FETCH внутрь цикла, так чтобы выбрав строку, вы могли переместив набор значений из этой строки в переменные, возвращались обратно в цикл чтобы переместить следующий набор значений в те же самые переменные. Например, возможно вам нужно чтобы вывод выдавался по одной строке, спрашивая каждый раз у пользователя, хочет ли он продолжить чтобы увидеть следующую строку</p>
<pre><code>Look_at_more:=True;
EXEC SQL OPEN CURSOR Londonsales;
while Look_at_more do
begin
EXEC SQL FETCH Londonsales
INTO :id_num, :Salesperson, :loc, :comm;
writeln (id_num, Salesperson, loc, comm);
writeln ('Do you want to see more data? (Y/N)');
readln (response);
it response='N' then Look_at_more:=False
end;
EXEC SQL CLOSE CURSOR Londonsales;
</code></pre>
<p>В Паскале, знак :=означает - &quot;является назначенным значением из&quot;, в то время как=еще имеет обычное значение &quot; равно &quot;. Функция writeln записывает ее вывод, и затем переходит к новой строке. Одиночные кавычки вокруг символьных значений во втором writeln и в предложении if ... then - обычны для Паскаля, что случается при дубликатах в SQL.</p>
<p>В результате этого фрагмента, Булева переменная с именем Look_at_more должна быть установлена в состояние верно, открыт курсор, и введен цикл. Внутри цикла, строка выбирается из курсора и выводится на экран.
У пользователя спрашивают, хочет ли он видеть следующую строку. Пока он не ответил N (Нет ), цикл повторяется, и следующая строка значений будет выбрана.
Хотя переменные Look_at_more и ответ должны быть обьявлены как Булева переменная и символьная(char) переменная, соответственно, в разделе обьявлений переменных в Паскаля, они не должны быть включены в раздел обьявлений SQL, потому что они не используются в командах SQL.
Как вы можете видеть, двоеточия перед именами переменных не используются для не-SQL операторов. Далее обратите внимание, что имеется оператор CLOSE CURSOR соответствующий оператору OPEN CURSOR. Он, как вы поняли, освобождает курсор значений, поэтому запрос будет нужно выполнить повторно с оператором OPEN CURSOR, прежде чем перейти в выбору следующих значений. Это необязательно для тех строк которые были выбраны запросом после закрытия курсора, хотя это и обычная процедура.
Пока курсор закрыт, SQL не следит за тем, какие строки были выбраны.
Если вы открываете курсор снова, запрос повторно выполняется с этой точки, и вы начинаете все сначала. Этот пример не обеспечивает автоматический выхода из цикла, когда все строки уже будут выбраны. Когда у FETCH нет больше строк которые надо извлекать, он просто не меняет значений в переменных предложения INTO. Следовательно, если данные исчерпались, эти переменные будут неоднократно выводиться с идентичными значениями, до тех пор пока пользователь не завершит цикл, введя ответ - N.</p>
<h3 id="sql-коды">SQL КОДЫ</h3>
<p>Хорошо было бы знать, когда данные будут исчерпаны, так чтобы можно было сообщить об этом пользователю и цикл завершился бы автоматически.
Это - даже более важно чем например знать что команда SQL выполнена с ошибкой. Переменная SQLCODE (называемая еще SQLCOD в ФОРТРАНе ) предназначена чтобы обеспечить эту функцию. Она должна быть определена как переменная главного языка и должна иметь тип данных который в главном языке соответствует одному из точных числовых типов SQL, как это показано в Приложении B. Значение SQLCODE устанавливается каждый раз, когда выполняется команда SQL. В основном существуют три возможности:
Команда выполнилась без ошибки, но не произвела никакого действия.</p>
<ul>
<li>Для различных команд это выглядит по разному: Для SELECT, ни одна строка не выбрана запросом.</li>
<li>Для FETCH, последняя строка уже была выбрана, или ни одной строки не выбрано запросом в курсоре.</li>
<li>Для INSERT, ни одной строки не было вставлено (подразумевается что запрос использовался чтобы сгенерировать значения для вставки, и был отвергнут при попытке извлечения любой строки.</li>
<li>Для UPDATE и DELETE, ни одна строка не ответила условию предиката, и следовательно никаких изменений сделано в таблице не будет.</li>
<li>В любом случае, будет установлен код SQLCODE=100.</li>
<li>Команда выполнилась нормально, не удовлетворив ни одному из выше указанных условий. В этом случае, будет установлен код SQLCOD=0.</li>
<li>Команда сгенерировала ошибку. Если это случилось, изменения сделанные к базе данных текущей транзакцией, будут восстановлены( см. Главу 23). В этом случае будет установлен код SQLCODE= некоторому отрицательному числу, определяемому проектировщиком. Задача этого числа, идентифицировать проблему, так точно насколько это возможно. В принципе, ваша система должна быть снабжена подпрограммой, которая в этом случае, должна выполниться чтобы выдать для вас информацию расшифровывающее значение негативного числа определенного вашим проектировщиком. В этом случае некоторое сообщение об ошибке будет выведено на экран или записано в файл протокола, а программа в это время выполнит восстановление изменений для текущей транзакции, отключится от базы данных и выйдет из нее. Теперь мы можем усовершенствовать</li>
</ul>
<h3 id="использование-sqlcode-для-управления-циклами">ИСПОЛЬЗОВАНИЕ SQLCODE ДЛЯ УПРАВЛЕНИЯ ЦИКЛАМИ</h3>
<p>Наш предыдущий пример для выхода из цикла автоматически, при условии что курсор пуст, все строки выбраны, или произошла ошибка:</p>
<pre><code>Look_at_more:=lhe;
EXEC SQL OPEN CURSOR Londonsales;
while Look_at_more
and SQLCODE=O do
begin
EXEC SQL FETCH London$ales
INTO :id_num, :Salesperson, :loc, :comm;
writeln (id_num, Salesperson, loc, comm);
writeln ('Do you want to see more data? (Y/N)');
readln (response);
If response='N' then Look_at_more:=Fabe;
end;
EXEC SQL CLOSE CURSOR Londonsales;
</code></pre>
<h3 id="предложение-whenever">ПРЕДЛОЖЕНИЕ WHENEVER</h3>
<p>Это удобно для выхода при выполненом условии - все строки выбраны.
Но если вы получили ошибку, вы должны предпринять нечто такое, что описано для третьего случая, выше. Для этой цели, SQL предоставляет предложение GOTO. Фактически, SQL позволяет вам применять его достаточно широко, так что программа может выполнить команду GOTO автоматически, если будет произведено определенное значение SQLCODE. Вы можете сделать это соввместно с предложением WHENEVER. Имеется кусгок из примера для этого случая:</p>
<pre><code>EXEC SQL WHENEVER SQLERROR GOTO Error_handler;
EXEC SQL WHENEVER NOT FOUND CONTINUE;
</code></pre>
<p>SQLERROR- это другой способ сообщить что SQLCODE &lt; 0; а NOT FOUND - это другой способ сообщить что SQLCODE=100. (Некоторые реализации называют последний случай еще как - SQLWARNING.) Error_handler - это имя того места в программе в которое будет перенесено выполнение программы если произошла ошибка (GOTO может состоять из одного или двух слов). Такое место определяется любым способом соответствующим для главного языка, например, с помощью метки в Паскале, или имени раздела или имени параграфа в КОБОЛЕ (в дальнейшем мы будем использовать термин - метка). Метка более удачно идентифицирует стандартную процедуру распространяемую проектировщиком для включения во все программы.
CONTINUE не делает чего-то специального для значения SQLCODE. Оно также является значением по умолчанию. если вы не используете команду WHENEVER, определяющую значение SQLCODE. Однако, эти неактивные определения дают вам возможность переключаться вперед и назад, выполняя и не выполняя действия, в различных точках(метках) вашей программы. Например, если ваша программа включает в себя несколько команд INSERT, использующих запросы, которые реально должны производить значения, вы могли бы напечатать специальное сообщение или сделать что-то такое, что поясняло бы, что запросы возвращаются пустыми и никакие значения не были вставлены. В этом случае, вы можете ввести следующее:</p>
<pre><code>EXEC SQL WHENEVER NOT FOUND GOTO No_rows;
</code></pre>
<p>No_rows - это метка в некотором коде, содержащем определенное действие. С другой стороны, если вам нужно сделать выборку в программе позже, вы можете ввести следующее в этой точке,</p>
<pre><code>EXEC SQL WHENEVER NOT FOUND CONTINUE;
</code></pre>
<p>что бы выполнение выборки повторялось до тех пор пока все строки не будут извлечены, что является нормальной процедурой не требующей специальной обработки.</p>
<h3 id="модифицирование-курсоров">МОДИФИЦИРОВАНИЕ КУРСОРОВ</h3>
<p>Курсоры могут также быть использованы, чтобы выбирать группу строк из таблицы, которые могут быть затем модифицированы или удалены одна за другой. Это дает вам возможность, обходить некоторые ограничения предикатов используемых в командах UPDATE и DELETE. Вы можете ссылаться на таблицу задействованную в предикате запроса курсора или любом из его подзапросов, которые вы не можете выполнить в предикатах самих этих команд. Как подчеркнуто в Главе 16, стандарт SQL отклоняет попытку удалить всех пользователей с рейтингом ниже среднего, в следующей форме:</p>
<pre><code>   EXEC SQL DELETE FROM Customers
</code></pre>
<p>WHERE rating &lt;
( SELECT AVG (rating)
FROM Customers);</p>
<p>Однако, вы можете получить тот же эффект, используя запрос для выбора соответствующих строк, запомнив их в курсоре, и выполнив DELETE с использованием курсора. Сначала вы должны обьявить курсор:</p>
<pre><code>EXEC SQL DECLARE Belowavg CURSOR FOR
SELECT *
FROM Customers
WHERE rating &lt;
(SELECT AVG (rating)
FROM Customers);
</code></pre>
<p>Затем вы должны создать цикл, чтобы удалить всех заказчиков выбранных курсором:</p>
<pre><code>EXEC SQL WHENEVER SQLERROR GOTO Error_handler;
EXEC SQL OPEN CURSOR Belowavg;
while not SOLCODE=100 do
begin
EXEC SOL FETCH Belowavg INTO :a, :b, :c, :d, :e;
EXEC SOL DELETE FROM Customers
WHERE CURRENT OF Belowavg;
end;
EXEC SOL CLOSE CURSOR Belowavg;
</code></pre>
<p>Предложение WHERE CURRENT OF означает что DELETE применяется к строке которая в настоящее время выбрана курсором. Здесь подразумевается, что и курсор и команда DELETE, ссылаются на одну и ту же таблицу, и следовательно, что запрос в курсоре - это не обьединение.
Курсор должен также быть модифицируемым. Являясь модифицируемым, курсор должен удовлетворять тем же условиям что и представления (см. Главу 21). Кроме того, ORDER BY и UNION, которые не разрешены в представлениях, в курсорах - разрешаются, но предохраняют курсор от модифицируемости. Обратите внимание в вышеупомянутом примере, что мы должны выбирать строки из курсора в набор переменных, даже если мы не собирались использовать эти переменные. Этого требует синтаксис команды FETCH. UPDATE работает так же. Вы можете увеличить значение комиссионных всем продавцам, которые имеют заказчиков с оценкой=300, следующим способом. Сначала вы обьявляете курсор:</p>
<pre><code>EXEC SOL DECLARE CURSOR High_Cust AS
SELECT *
FROM Salespeople
WHERE snum IN
(SELECT snum
FROM Customers
WHERE rating=300);
</code></pre>
<p>Затем вы выполняете модификации в цикле:</p>
<pre><code>EXEC SQL OPEN CURSOR High_cust;
while SQLCODE=0 do
begin
EXEC SOL FETCH High_cust
INTO :id_num, :salesperson, :loc, :comm;
EXEC SQL UPDATE Salespeople
SET comm=comm + .01
WHERE CURRENT OF High_cust;
end;
EXEC SQL CLOSE CURSOR High_cust;
</code></pre>
<p>Обратите внимание: что некоторые реализации требуют, чтобы вы указывали в определении курсора, что курсор будет использоваться для выполнения команды UPDATE на определенных столбцах. Это делается с помощью заключительной фразы определения курсора - FOR UPDATE <column list="">.
Чтобы обьявить курсор High_cust таким способом, так чтобы вы могли модифицировать командой UPDATE столбец comm, вы должны ввести следующее предложение:</column></p>
<pre><code>EXEC SQL DECLARE CURSOR High_Cust AS
SELECT *
FROM Salespeople
WHERE snum IN
(SELECT snum
FROM Customers
WHERE rating=300)
FOR UPDATE OF comm;
</code></pre>
<p>Это обеспечит вас определенной защитой от случайных модификаций, которые могут разрушить весь порядок в базе данных.</p>
<h3 id="переменная-indicator">ПЕРЕМЕННАЯ INDICATOR</h3>
<p>Пустые (NULLS) значения - это специальные маркеры определяемые самой SQL. Они не могут помещаться в главные переменные. Попытка вставить NULL значения в главнуюпеременную будет некорректна, так как главные языки не поддерживают NULL значений в SQL, по определению. Хотя результат при попытке вставить NULL значение в главную переменную определяет проектировщик, этот результат не должен ротиворечить теории базы данных, и поэтому обязан произвести ошибку: код SQLCODE ввиде отрицательного числа, и вызвать подпрограмму управления ошибкой. Естеcтвенно вам нужно этого избежать. Поэтому, вы можете выбрать NULL значения с допустимыми значениями, не приводящими к разрушению вашей программы. Даже если программа и не разрушится, значения в главных переменных станут неправильными, потому что они не могут иметь NULL значений. Альтернативным методом предоставляемым для этой ситуацией является - функция переменной indicator(указатель). Переменная indicator - обьявленная в разделе объявлений SQL напоминает другие переменные. Она может иметь тип главного языка который соответствует числовому типу в SQL. Всякий раз, когда вы выполняете операцию, которая должна поместить NULL значение в переменную главного языка, вы должны использовать переменную indicator, для надежности. Вы помещаете переменную indicator в команду SQL непосредственно после переменной главного языка которую вы хотите защитить, без каких-либо пробелов или запятых, хотя вы и можете, при желании, вставить слово - INDICATOR. Переменной indicator в команде, изначально присваивается значение 0. Однако, если производится значение NULL, переменная indicator становится равной отрицательному числу. Вы можете проверить значение переменной indicator, чтобы узнать, было ли найдено значение NULL. Давайте предположим, что поля city и comm, таблицы Продавцов, не имеют ограничения NOT NULL, и что мы объявили вразделе обьявлений SQL, две ПАСКАЛЬевские переменные</p>
<p>целого типа, i_a и i_b. (Нет ничего такого в разделеобьявлений, что могло бы представить их как переменные indicator. Они станут переменными indicator, когда будут использоваться как переменные indicator. )
Имеется одна возможность:</p>
<pre><code>EXEC SQL OPEN CURSOR High_cust;
while SQLCODE=O do
begin
EXEC SQL FETCH High_cust
INTO :id_num, :salesperson,
:loc:i_a, :commINDlCATOR:i_b;
If i_a &gt;=O and i_b &gt;=O then
{no NULLs produced}
EXEC SQL UPDATE Salespeople
SET comm=comm + .01
WHERE CURRENT OF Hlgh_cust;
else
{one or both NULL}
begin
If i_a &lt; O then
writeln ('salesperson ', id_num, ' has no city');
If i_b &lt; O then
writeln ('salesperson ', id_num, ' has no
commission');
end;
{else}
end; {while}
EXEC SQL CLOSE CURSOR High_cust;
</code></pre>
<p>Как вы видите, мы включили, ключевое слово INDICATOR в одном случае, и исключили его в другом случае, чтобы показать, что эффект будет одинаковым в любом случае. Каждая строка будет выбрана, но команда UPDATE выполнится только если NULL значения не будут обнаружены. Если будут обнаружены NULL значения, выполнится еще одна часть программы, которая распечатает предупреждающее сообщение, где было найдено каждое NULL значение.
Обратите внимание: переменные indicator должны проверяться в главном языке, как указывалось выше, а не в предложении WHERE команды SQL. Последнее в принципе не запрещено, но результат часто бывает непредвиденным.</p>
<h3 id="использование-переменной-indicator-для-эмуляции-null-значений-sql">ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННОЙ INDICATOR ДЛЯ ЭМУЛЯЦИИ NULL ЗНАЧЕНИЙ SQL</h3>
<p>Другая возможность состоит в том, чтобы обрабатывать переменную indicator, связывая ее с каждой переменной главного языка, специальным способом, эмулирующим поведение NULL значений SQL.
сякий раз, когда вы используете одно из этих значений в вашей программе, например в предложении if ... then, вы можете сначала проверить связанную переменную indicator, является ли ее значение=NULL. Если это так, то вы обрабатываете переменную по-другому. Например, если NULL значение было извлечено из поля city для главной переменной city, которая связана с переменной indicator - i_city, вы должны установить значение city равное последовательности пробелов. Это будет необходимо, только если вы будете распечатывать его на принтере; его значение не должно отличаться от логики вашей программы. Естественно, i_city автоматически установливается в отрицательное значение. Предположим, что вы имели следующую конструкцию в вашей программе:</p>
<pre><code>If sity='London' then
comm:=comm + .01
else comm:=comm - .01
</code></pre>
<p>Любое значение, вводимое в переменную city, или будет равно &quot;London&quot; или не будет равно. Следовательно, в каждом случае значение комиссионных будет либо увеличино либо уменьшено. Однако, эквивалентные команды в SQL выполняются по разному:</p>
<pre><code>EXEC SQL UPDATE Salespeople
SET comm=comm + .01
WHERE sity='London';
и
EXEC SQL UPDATE Salespeople
SET comm=comm .01;
WHERE sity &lt; &gt; 'London';
</code></pre>
<p>( Вариант на ПАСКАЛе работает только с единственным значением, в то время как вариант на SQL работает со всеми таблицами. ) Если значение city в варианте на SQL будет равно значению NULL, оба предиката будут неизвестны, и значение comm, следовательно, не будет изменено в любом случае.
Вы можете использовать переменную indicator чтобы сделать поведение вашего главного языка непротиворечащим этому, с помощью создания условия, которое исключает NULL значения:</p>
<pre><code>If i_city &gt;=O then
begin
If city='London' then
comm:=comm + .01
else comm:=comm - .01;
end;
{begin and end нужны здесь только для понимания}
--------------------------------------------------------------
ПРИМЕЧАНИЕ: Последняя строка этого примера содержит ремарку -
{ begin и end необходимы только для понимания }
--------------------------------------------------------------
</code></pre>
<p>В более сложной программ, вы можете захотеть установить Булеву переменную в &quot;верно&quot;, чтобы указать что значение city=NULL. Затем вы можете просто проверять эту переменную всякий раз, когда вам это необходимо.</p>
<h3 id="другое-использование-переменной-indicator">ДРУГОЕ ИСПОЛЬЗОВАНИЕ ПЕРЕМЕННОЙ INDICATOR</h3>
<p>Переменная indicator также может использоваться для назначения значения NULL. Просто добавьте ее к имени главной переменной в команде UPDATE или INSERT тем же способом что и в команде SELECT. Если переменная indicator имеет отрицательное значение, значение NULL будет помещено в поле. Например, следующая команда помещает значения NULL в поля city и comm, таблицы Продавцов, всякий раз, когда переменные indicator - i_a или i_b будут отрицательными; в противном случае она помещает туда значения главных переменных:</p>
<pre><code>EXEC SQL INSERT INTO Salespeople
VALUES (:Id_num, :salesperson, :loc:i_a, :comm:i_b);
</code></pre>
<p>Переменная indicator используется также, чтобы показывать отбрасываемую строку. Это произойдет если вы вставляете значения символов SQL в главную переменную которая не достаточно длинна чтобы вместить все символы. Это особая проблема с нестандартным типами данных - VARCHAR и LONG (смотри Приложению C). В этом случае, переменная будет заполнена первыми символами строки, а последние символы будут потеряны. Если используется переменная indicator, она будет установлена в положительное значение, указывающее на длину отбрасываемой части строки, позволяя таким образом вам узнать, сколько символов было потеряно.
В этом случае, Вы можете проверить с помощью просмотра -значение переменной indicator &gt; 0, или &lt; 0.</p>
<h3 id="резюме-19">РЕЗЮМЕ</h3>
<p>Команды SQL вкладываются в процедурные языках, чтобы объединить силы двух подходов. Некоторые дополнительные средства SQL необходимы, чтобы выполнить эту работу. Вложенные команды SQL транслируемые программой, называемой прекомпилятором, в форму пригодную для использования транслятором главного языка, и используемые в этом главном языке, как вызовы процедуры к подпрограммам которые создает прекомпилятор, называются - модулями доступа. ANSI поддерживает вложение SQL в языки: ПАСКАЛЬ, ФОРТРАН, КОБОЛ, и PL/I. Другие языки также используются, особенно Си. В попытке кратко описать вложенный SQL, имеются наиболее важные места в этой главе:</p>
<ul>
<li>Все вложенные команды SQL начинаются словами EXEC SQL и заканчиваются способом который зависит от используемого главного языка.</li>
<li>Все главные переменные доступные в командах SQL, должны быть обьявлены в разделе объявлений SQL прежде, чем они будут использованы.</li>
<li>Всем главным переменным должно предшествовать двоеточие когда они используются в команде SQL.</li>
<li>Запросы могут сохранять свой вывод непосредственно в главных переменных, используя предложение INTO, если и только если, они выбирают единственную строку.</li>
<li>Курсоры могут использоваться для сохранения вывода запроса, и доступа к одной строке в каждый момент времени. Курсоры бывают обьявлеными (если определяют запрос в котором будут содержаться), открытыми(если выполняют запрос ), и закрытыми (если удаляют вывод запроса из курсора). Если курсор открыт, команда FETCH, используется чтобы перемещать его по очереди к каждой строке вывода запроса.</li>
<li>Курсоры являются модифицируемыми или только-чтение. Чтобы стать модифицируемым, курсор должен удовлетворять всем критериям которым удовлетворяет просмотр; кроме того, он не должен использовать предложений ORDER BY или UNION, которые в любом случае не могут использоваться просмотрами. Не модифицируемый курсор является курсором только-чтение.</li>
<li>Если курсор модифицируемый, он может использоваться для определения, какие строки задействованы вложенными командами UPDATE и DELETE через предложение WHERE CURRENT OF. DELETE или UPDATE должны быть вне той таблицы к которой курсор обращается в запросе.</li>
<li>SQLCODE должен быть обьявлен как переменная числового типа для каждой программы которая будет использовать вложенный SQL. Его значение установливается автоматически после выполнения каждой команды SQL.</li>
<li>Если команда SQL выполнена как обычно, но не произвела вывода или ожидаемого изменения в базе данных, SQLCODE=100. Если команда произвела ошибку, SQLCODE будет равняться некоторому аппаратноопределенному отрицательному числу которое описывает ошибку. В противном случае, SQLCODE=0.</li>
<li>Предложение WHENEVER может использоваться для определения действия которое нужно предпринять когда SQLCODE=100 (не найдено) или когда SQLCODE равен отрицательному числу (SQLERROR). Действием может быть или переход к некоторой определенной метке в программе (GOTO <label> ) или отсутствие какого-либо действия вообще( продолжить). Последнее, установлено по умолчанию.</label></li>
<li>Числовые переменные могут также использоваться как переменные indicator. Переменные indicator следуют за другим именами переменных в команде SQL, без каких бы то ни было посторонних символов кроме (необязательного) слова INDICATOR.</li>
<li>Обычно, значение переменной indicator=0. Если команда SQL пытается поместить NULL значение в главную переменную которая использует indicator, indicator будет установлен в отрицательное значение. Этот факт можно использоваться чтобы предотвращать ошибки, и для помечания NULL значений SQL для специальной обработки их в главной программе.</li>
<li>Переменная indicator может использоваться для вставки NULL значений в команды SQL - INSERT или UPDATE. Она также может принимать положительное значение указывающее на длинну отбрасываемой части строки не поместившейся в предельные границы какойнибудь переменной, куда эта строка помещалась.</li>
</ul>
<h3 id="работа-с-sql-15">РАБОТА С SQL</h3>
<p>Обратите внимание: Ответы для этих упражнений написаны в псевдокодах, являющихся английским языком описания логики, которой должна следовать программа. Это сделано для того чтобы помомочь читателям которые могут быть незнакомы с Паскалем(или любым другим языком). Кроме того это лучше сфокусирует ваше внимание на включемых понятиях, опуская частности того или другого языка. Чтобы непротиворечить нашим примерам, стиль псевдокода будет напоминать Паскаль.
Мы опустим из программ все что не относится напрямую к рассматриваемым вопросам, например, определение устройств ввода-вывода, подключение к базе данных, и так далее. Конечно, имеется много способов чтобы выполнять такие упражнения; и совсем не обязательно что представленые варианты решений являются самыми удачными.</p>
<ul>
<li><p>Разработайте простую программу которая выберет все комбинации полей snum и cnum из таблиц Порядков и Заказчиков и выясните, всегда ли предыдущая комбинация такая же как последующая. Если комбинация из таблицы Порядков не найдена в таблице Заказчиков, значение поля snum для этой строки будет изменено на удовлетворяющее условию совпадения. Вы должны помнить, что курсор с подзапросом - модифицируем (ANSI ограничение, также применимо к просмотрам, и что базисная целостность базы данных это не тоже самое что проверка на ошибку(т.е. первичные ключи уникальны, все поля cnums в таблице Порядков правильны, и так далее). Проверьте раздел обьявлений, и убедитесь что там обьявлены все используемые курсоры.</p>
</li>
<li><p>Предположим, что ваша программа предписывает ANSI запрещение курсоры или просмотры использующие модифицируемые подзапросы. Как вы должны изменить вышеупомянутую программу?</p>
</li>
<li><p>Разработайте программу которая подсказывает пользователям изменить значения поля city продавца, автоматически увеличивает комиссионные на .01 для продавца переводимого в Барселону и уменьшает их на .01 для продавца переводимого в Сан Хосе. Кроме того, продавец находящийся в Лондоне должен потерять .02 из своих комиссионных, независимо от того меняет он город или нет, в то время как продавец не находящийся в Лондоне должен иметь увеличение комиссионных на .02. Изменение в комиссионных основывающееся на нахождении продавца в Лондоне, может применяться независимо от того куда тот переводится. Выясните могут ли поле city или поле comm содержать NULL значения, и обработайте их, как это делается в SQL. Предупреждение! : эта программа имеет некоторые сокращения.</p>
</li>
</ul>
<h2 id="приложение-a">Приложение A</h2>
<p>ОТВЕТЫ ДЛЯ УПРАЖНЕНИЙ</p>
<h3 id="глава-1">Глава 1</h3>
<ol>
<li><p>cnum</p>
</li>
<li><p>rating</p>
</li>
<li><p>Другим словом для строки является - запись. Другим словом для столбца
является - поле.</p>
</li>
<li><p>Потому что строки, по определению, находятся без какого либо
определенного упорядочения.</p>
</li>
</ol>
<h3 id="глава-2">Глава 2</h3>
<ol>
<li><p>Символ ( или текст ) и номер</p>
</li>
<li><p>Нет</p>
</li>
<li><p>Язык Манипулирования Данными (ЯЗЫК DML)</p>
</li>
<li><p>Это слово в SQL имеет специальное учебное значение.</p>
</li>
</ol>
<h3 id="глава-3">Глава 3</h3>
<pre><code>1. SELECT onum, amt, odate 
     FROM Orders; 
 
2. SELECT * 
      FROM Customers 
      WHERE snum = 1001; 
 
3 SELECT city, sname, snum, comm 
     FROM Salespeople; 
 
4. SELECT rating, cname 
      FROM Customers 
      WHERE city = 'SanJose'; 
 
5. SELECT DISTINCT snum 
      FROM Orders; 
 
</code></pre>
<h3 id="глава-4">Глава 4</h3>
<pre><code>1. SELECT * FROM Orders WHERE amt &gt; 1000; 
 
2. SELECT sname, city 
      FROM Salespeople 
      WHERE city = 'London' 
        AND comm &gt; .10; 
 
3. SELECT * 
      FROM Customers 
      WHERE rating &gt; 100 
        OR city = 'Rome'; 
 
 или 
  SELECT * 
     FROM Customers 
     WHERE NOT rating &lt; = 100 
       OR city = 'Rome'; 
 или 
  SELECT * 
     FROM Customers 
     WHERE NOT (rating &lt; = 100 
       AND city &lt; &gt; 'Rome'); 
 
Могут быть еще другие решения. 
 
 
4. onum      amt   odate    cnum  snum 
 
   3001      18.69  10/03/1990  2008  1007 
 
   3003     767.19  10/03/1990  2001  1001 
 
   3005    5160.45  10/03/1990  2003  1002 
 
   3009    1713.23  10/04/1990  2002  1003 
 
   3007      75.75  10/04/1990  2004  1002 
 
   3008    4723.00  10/05/1990  2006  1001 
 
   3010    1309.95  10/06/1990  2004  1002 
 
   3011    9891.88  10/06/1990  2006  1001 
 
5. onum    amt      odate   cnum  snum 
 
   3001    18.69    10/03/1990  2008  1007 
 
   3003    767.19   10/03/1990  2001  1001 
 
 
  onum    amt    odate     cnum snum 
 
  3006  1098.16  10/03/1990   2008  1007 
 
  3009  1713.23  10/04/1990   2002  1003 
 
  3007  75.75    10/04/1990   2004  1002 
 
  3008  4723.00  10/05/1990   2006  1001 
 
  3010  1309.95  10/06/1990   2004  1002 
 
  3011  9891.88  10/06/1990   2006  1001 
 
6. SELECT * 
      FROM Salespeople; 
</code></pre>
<h3 id="глава-5">Глава 5</h3>
<pre><code>1. SELECT * 
      FROM Orders 
      WHERE odate IN (10/03/1990,10/04/1990); 
 
   и 
   SELECT * 
      FROM Orders 
      WHERE odate BETWEEN 10/03/1990 AND 10/04,1990; 
 
2. SELECT * 
      FROM Customers 
      WHERE snum IN (1001,1004); 
 
3. SELECT * 
      FROM Customers 
      WHERE cname BETWEEN 'A' AND 'H'; 
</code></pre>
<blockquote>
<p>ПРИМЕЧАНИЕ: ВЫ ASCII базовой системе Hoffman не будет выве ден из-за конечных пробелов после H. По той же самой причине вторая граница не может быть G, поскольку она не выведет имена Giovanni и Grass. G может использоваться в сопровождении с Z, так чтобы следовать за другими символами в алфавитном порядке, а не предшествовать им, как это делают пробелы.</p>
</blockquote>
<pre><code>4. SELECT * 
      FROM Customers 
      WHERE cname LIKE 'C%'; 
 
5. SELECT * 
      FROM Orders 
      WHERE amt &lt; &gt; O 
         AND (amt IS NOT NULL); 
  или 
   SELECT * 
      FROM Orders 
      WHERE NOT (amt = O 
         OR amt IS NULL); 
</code></pre>
<h3 id="глава-6">Глава 6</h3>
<pre><code>1. SELECT COUNT(*) 
      FROM Orders 
      WHERE odate = 10/03/1990; 
 
2. SELECT COUNT (DISTINCT city) 
      FROM Customers; 
 
3. SELECT cnum, MIN (amt) 
      FROM Orders 
      GROUP BY cnum; 
 
4. SELECT MIN (cname) 
     FROM Customers 
     WHERE cname LIKE 'G%'; 
 
5. SELECT city, 
      MAX (rating) 
      FROM Customers 
  GROUP BY city; 
</code></pre>
<ol start="6">
<li>SELECT odate, count (DISTINCT snum
FROM Orders
GROUP BY odate;</li>
</ol>
<h3 id="глава-7">Глава 7</h3>
<pre><code>1. SELECT onum, snum, amt * .12 
      FROM Orders; 
 
2. SELECT 'For the city ', city, ', the highest rating is ',  &quot;, 
   MAX (rating) 
      FROM Customers 
      GROUP BY city; 
 
3. SELECT rating, cname, cnum 
     FROM Customers 
     ORDER BY rating DESC; 
 
4. SELECT odate, SUM (amt) 
      FROM Orders 
      GROUP BY odate 
      ORDER BY 2 DESC; 
</code></pre>
<h3 id="глава-8">Глава 8</h3>
<pre><code>1. SELECT onum, cname 
      FROM Orders, Customers 
      WHERE Customers.cnum = Orders.cnum; 
 
2. SELECT onum, cname, sname 
      FROM Orders, Customers, Salespeople 
      WHERE Customers.cnum = Orders.cnum 
        AND Salespeople.snum = Orders.snum; 
 
3. SELECT cname, sname, comm 
      FROM Salespeople, Customers 
      WHERE Salespeople.snum = Customers.snum 
        AND comm * .12; 
 
4. SELECT onum, comm * amt 
      FROM Salespeople, Orders, Customers 
      WHERE rating &gt; 100 
        AND Orders.cnum = Customers.cnum 
        AND Orders.snum = Salespeople.snum; 
</code></pre>
<h3 id="глава-9">Глава 9</h3>
<pre><code>1. SELECT first.sname, second.sname 
      FROM Salespeople first, Salespeople second 
      WHERE first.city = second.city 
        AND first.sname &lt; second.sname; 
 
Псевдонимам нет необходимости иметь именно такие имена. 
 
2. SELECT cname, first.onum, second.onum 
      FROM Orders first, Orders second, Customers 
      WHERE first.cnum = second.cnum 
        AND first.cnum = Customers.cnum 
        AND first.onum &lt; second.onum; 
Ваш вывод может иметь некоторые отличи, но в вашем ответе все логические компоненты должны быть такими же.
 
3. SELECT a.cname, a.city 
      FROM Customers a, Customers b 
      WHERE a.rating = b.rating 
        AND b.cnum = 2001; 
</code></pre>
<h3 id="глава-10">Глава 10</h3>
<pre><code>1. SELECT * 
      FROM Orders 
      WHERE cnum = 
      (SELECT cnum 
          FROM Customers 
          WHERE cname = 'Cisneros'); 
 
  или 
   SELECT * 
      FROM Orders 
      WHERE cnum IN 
        (SELECT cnum 
            FROM Customers 
            WHERE cname = 'Cisneros'); 
 
2. SELECT DISTINCT cname, rating 
      FROM Customers, Orders 
      WHERE amt &gt; 
        (SELECT AVG (amt) 
            FROM Orders) 
        AND Orders.cnum = Customers.cnum; 
 
3. SELECT snum, SUM (amt) 
     FROM Orders 
     GROUP BY snum 
     HAVING SUM (amt) &gt; 
        (SELECT MAX (amt) 
            FROM Orders); 
 
</code></pre>
<h3 id="глава-11">Глава 11</h3>
<pre><code>1. SELECT cnum, cname 
      FROM Customers outer 
      WHERE rating = 
        (SELECT MAX (rating) 
         FROM Customers inner 
         WHERE inner.city = outer.city); 
 
2. Решение с помощью соотнесенного подзапроса: 
 
   SELECT snum, sname 
      FROM Salespeople main 
      WHERE city IN 
        (SELECT city 
            FROM Customers inner 
            WHERE inner.snum &lt; &gt; main.snum); 
 
   Решение с помощью объединения: 
 
   SELECT DISTINCT first.snum, sname 
      FROM Salespeople first, Customers second 
      WHERE first.city = second.city 
         AND first.snum &lt; &gt; second.snum; 
</code></pre>
<p>Соотнесенный подзапрос находит всех заказчиков, не обслуживаемых данным продавцом, и выясняет: живет ли кто-нибудь из их в его городе. Решение с помощью объединения является более простым и более инту- итивным. Оно находит случаи где пол city совпадают, а пол snums нет. Следовательно объединение является более изящным решением для этой проблемы, чем то которое мы исследовали до этого. Имеется еще более изящное решение с помощью подзапроса, с которым Вы столкнетесь позже.</p>
<h3 id="глава-12">Глава 12</h3>
<pre><code>1. SELECT * 
      FROM Salespeople first 
      WHERE EXISTS 
        (SELECT * 
            FROM Customers second 
            WHERE first.snum = second.snum 
              AND rating = 300); 
 
2. SELECT a.snum, sname, a.city, comm 
      FROM Salespeople a, Customers b 
      WHERE a.snum = b.snum 
        AND b.rating = 300; 
 
3. SELECT * 
      FROM Salespeople a 
      WHERE EXISTS 
        (SELECT * 
            FROM Customers b 
            WHERE b.city = a.city 
              AND a.snum &lt; &gt; b.snum); 
 
4. SELECT * 
      FROM Customers a 
      WHERE EXISTS 
       (SELECT * 
           FROM Orders b 
           WHERE a.snum = b.snum 
             AND a.cnum &lt; &gt; b.cnum) 
</code></pre>
<h3 id="глава-13">Глава 13</h3>
<pre><code>1. SELECT * 
      FROM Customers 
      WHERE rating &gt; = ANY 
        (SELECT rating 
            FROM Customers 
            WHERE snum = 1002); 
 
2.   cnum   cname    city   rating   snum 
 
     2002   Giovanni  Rome      200     1003 
 
     2003   Liu       San Jose  200     1002 
 
     2004   Grass     Berlin    300     1002 
 
     2008   Cisneros  SanJose   300     1007 
 
3.  SELECT * 
       FROM Salespeople 
       WHERE city &lt; &gt; ALL 
         (SELECT city 
             FROM Customers); 
 
 или 
 
  SELECT * 
     FROM Salespeople 
     WHERE NOT city = ANY 
       (SELECT city 
           FROM Customers); 
 
4.  SELECT * 
       FROM Orders 
       WHERE amt &gt; ALL 
         (SELECT amt 
             FROM Orders a, Customers b 
             WHERE a.cnum = b.cnum 
               AND b.city = 'London'); 
 
5.  SELECT * 
       FROM Orders 
       WHERE amt &gt; 
         (SELECT MAX (amt) 
             FROM Orders a, Customers b 
             WHERE a.cnum = b.cnum 
               AND b.city = 'London'); 
</code></pre>
<h3 id="глава-14">Глава 14</h3>
<pre><code>1.  SELECT cname, city, rating, 'High Rating' 
       FROM Customers 
       WHERE rating &gt; = 200 
 
       UNION 
 
    SELECT cname, city, rating, ' Low Ratlng' 
       FROM Customers 
       WHERE rating &lt; 200; 
 
   или 
 
    SELECT cname, city, rating, 'High Rating' 
       FROM Customers 
       WHERE rating &gt; = 200 
 
       UNION 
 
       SELECT cname, city, rating, ' Low Rating' 
          FROM Customers 
          WHERE NOT rating &gt; = 200; 
</code></pre>
<p>Различие между этими двум предложениями, в форме второго предиката. Обратите внимание что, в обоих случаях, строка &quot;Low Rating&quot; имеет в начале дополнительный пробел для того чтобы совпадать со строкой &quot;High Rating&quot; по длине.</p>
<pre><code>2. SELECT cnum, cname 
      FROM Customers a 
      WHERE 1 &lt; 
       (SELECT COUNT (-) 
           FROM Orders b 
           WHERE a.cnum = b.cnum) 
 
           UNION 
 
   SELECT snum, sname 
      FROM Salespeople a 
      WHERE 1 &lt; 
        (SELECT COUNT (*) 
            FROM Orders b 
            WHERE a.snum = b.snum) 
 
      ORDER BY 2; 
 
3. SELECT snum 
      FROM Salespeople 
      WHERE city = 'San Jose' 
 
      UNION 
 
  (SELECT cnum 
      FROM Customers 
      WHERE city = 'San Jose' 
 
      UNION ALL 
 
  SELECT onum 
     FROM Orders 
     WHERE odate = 10/03/1990); 
     
</code></pre>
<h3 id="глава-15">Глава 15</h3>
<pre><code>1. INSERT INTO Salespeople (city, cname, comm, cnum) 
VALUES ('San Jose', 'Blanco', NULL, 1100); 

2. DELETE FROM Orders WHERE cnum = 2006; 

3. UPDATE Customers 
SET rating = rating + 100 
WHERE city = 'Rome'; 

4. UPDATE Customers 
SET snum = 1004 
WHERE snum = 1002; 
</code></pre>
<h3 id="глава-16">Глава 16</h3>
<ol>
<li><p>INSERT INTO Multicust
SELECT *
FROM Salespeople
WHERE 1 &lt;
(SELECT COUNT (*)
FROM Customers
WHERE Customers.snum = Salespeople.snum);</p>
<ol start="2">
<li><p>DELETE FROM Customers
WHERE NOT EXISTS
(SELECT *
FROM Orders
WHERE cnum = Customers.cnum);</p>
</li>
<li><p>UPDATE Salespeople
SET comm = comm + (comm * .2)
WHERE 3000 &lt;
(SELECT SUM (amt)
FROM Orders
WHERE snum = Salespeople.snum);
В более сложный вариант этой команды можно было бы вставить проверку чтобы убедиться, что значения комиссионных не превышают 1.0 ( 100 % ):</p>
</li>
</ol>
<p>UPDATE Salespeople
SET comm = comm + (comm * .2)
WHERE 3000 &lt;
(SELECT SUM (amt)
FROM Orders
WHERE snum = Salespeople.snum)
AND comm + (comm * .2) &lt; 1.0;
Эти проблемы могут иметь другие, такие же хорошие решения.</p>
</li>
</ol>
<h3 id="глава-17">Глава 17</h3>
<pre><code>1. CREATE TABLE Customers 
(cnum   integer, 
cname  char(10), 
city    char(10), 
rating  integer, 
snum   integer); 

2. CREATE INDEX Datesearch ON Orders(odate); 

( Все индексные имена используемые в этих ответах - произвольные. ) 

3. CREATE UNIQUE INDEX Onumkey ON Orders(onum); 

4. CREATE INDEX Mydate ON Orders(snum, odate); 

5. CREATE UNIQUE INDEX Combination ON 
Customers(snum, rating);
</code></pre>
<h3 id="глава-18">Глава 18</h3>
<pre><code>1. CREATE TABLE Orders 
(onum   integer NOT NULL PRIMARY KEY, 
amt    decimal, 
odate  date NOT NULL, 
cnum  integer NOT NULL, 
snum  integer NOT NULL, 
UNIOUE (snum, cnum)); 

или 

CREATE TABLE Orders 
(onum   integer NOT NULL UNIQUE, 
amt    decimal, 
odate  date NOT NULL, 
cnum  integer NOT NULL, 
snum  integer NOT NULL, 
UNIQUE (snum, cnum)); 

Первое решение предпочтительнее. 

2. CREATE TABLE Salespeople 
(snum   integer NOT NULL PRIMARY KEY, 
sname  char(15) CHECK (sname BETWEEN 'AA' AND 'MZ'), 
city    char(15), 
comm  decimal NOT NULL DEFAULT = .10); 

3.  CREATE TABLE Orders 
(onum   integer NOT NULL, 
amt    decimal, 
odate  date, 
cnum  integer NOT NULL, 
snum  integer NOT NULL, 
CHECK ((cnum &gt; snum) AND (onum &gt; cnum))); 
</code></pre>
<h3 id="глава-19">Глава 19</h3>
<pre><code>1. CREATE TABLE Cityorders 
(onum   integer NOT NULL PRIMARY KEY, 
amt    decimal, 
cnum  integer, 
snum  integer, 
city   char (15), 
FOREIGN KEY (onum, amt, snum) 
    REFERENCES Orders (onum, amt, snum), 
FOREIGN KEY (cnum, city) 
    REFERENCES Customers (cnum, city) ); 

2. CREATE TABLE Orders 
(onum   integer NOT NULL, 
amt    decimal, 
odate  date, 
cnum  integer NOT NULL, 
snum  integer, 
prev   integer, 
    UNIQUE (cnum, onum), 
    FOREIGN KEY (cnum, prev) REFERENCES Orders (cnum,onum) );9 
</code></pre>
<h3 id="глава-20">Глава 20</h3>
<pre><code>1. CREATE VIEW Highratings 
      AS SELECT * 
         FROM Customers 
         WHERE rating = 
           (SELECT MAX (rating) 
            FROM Customers); 
 
 
2. CREATE VIEW Citynumber 
      AS SELECT city, COUNT (DISTINCT snum) 
         FROM Salespeople 
         GROUP BY city; 
 
3. CREATE VIEW Nameorders 
      AS SELECT sname, AVG (amt), SUM (amt) 
         FROM Salespeople, Orders 
         WHERE Salespeople.snum = Orders.snum 
         GROUP BY sname; 
 
4. CREATE VIEW Multcustomers 
     AS SELECT * 
        FROM Salespeople a 
        WHERE 1 &lt; 
          (SELECT COUNT (*) 
              FROM Customers b 
              WHERE a.snum = b.snum); 
</code></pre>
<h3 id="глава-21">Глава 21</h3>
<pre><code>1. #1 - не модифицируемый, потому что он использует DISTINCT. 
   #2 - не модифицируемый, потому что он использует объединение, 
          агрегатную функцию, и GROUP BY. 
   #3 - не модифицируемый, потому что он основывается на #1, который 
          сам по себе не модифицируемый. 
 
2. CREATE VIEW Commissions 
      AS SELECT snum, comm 
         FROM Salespeople 
         WHERE comm BETWEEN .10 AND .20 
         WITH CHECK OPTION; 
 
3. CREATE TABLE Orders 
     (onum integer NOT NULL PRIMARY KEY, 
      amt decimal, 
      odate date DEFAULT VALUE = CURDATE, 
      snum integer, 
      cnum integer); 
  CREATE VIEW Entryorders 
     AS SELECT onum, amt, snum, cnum 
     FROM Orders; 
 
</code></pre>
<h3 id="глава-22">Глава 22</h3>
<pre><code>1. GRANT UPDATE (rating) ON Customers TO Janet; 
 
2. GRANT SELECT ON Orders TO Stephen WITH GRANT OPTION; 
 
3. REVOKE INSERT ON Salespeople FROM Claire; 
 
4. Шаг 1: CREATE VIEW Jerrysview 
             AS SELECT * 
                FROM Customers 
                WHERE rating BETWEEN 100 AND 500 
                WITH CHECK OPTION; 
 
   Шаг 2: GRANT INSERT, UPDATE ON Jerrysview TO Jerry; 
 
5. Шаг 1: CREATE VIEW Janetsview 
             AS SELECT * 
                FROM Customers 
                WHERE rating = 
                   (SELECT MIN (rating) 
                       FROM Customers); 
 
   Шаг 2: GRANT SELECT ON Janetsview TO Janet; 
 
</code></pre>
<h3 id="глава-23">Глава 23</h3>
<pre><code>1. CREATE DBSPACE Myspace 
      (pctindex 15, 
       pctfree 40); 
 
2. CREATE SYNONYM Orders FOR Diane.Orders; 
 
3. Они должны быть откатаны обратно назад. 
 
4. Блокировка взаимоисключающего доступа. 
 
5. Только чтение 
</code></pre>
<h3 id="глава-24">Глава 24</h3>
<pre><code>1. SELECT a.tname, a.owner, b.cname, b.datatype 
      FROM SYSTEMCATOLOG a, SYSTEMCOLUMNS b 
      WHERE a.tname = b.tname 
        AND a.owner = b.owner 
        AND a.numcolumns &gt; 4; 
</code></pre>
<p>Обратите Внимание: из-за того что большинство имен столбца объединяемых таблиц - различны, не все из используемых псевдонимов a и b в вышеупомянутой команде - строго обязательны. Они представлены просто для понимания.</p>
<pre><code>2. SELECT tname, synowner, COUNT (ALL synonym) 
      FROM SYTEMSYNONS 
      GROUP BY tname, synowner; 
 
3 SELECT COUNT (*) 
     FROM SYSTEMCATALOG a 
     WHERE numcolumns/2 &lt; 
       (SELECT COUNT (DISTINCT cnumber) 
           FROM SYSTEMINDEXES b 
           WHERE a.owner = b.tabowner 
             AND a.tname = b.tname); 
</code></pre>
<p>Глава 25</p>
<pre><code>1.  EXEC SQL BEGIN DECLARE SECTION; 
       SQLCODE:integer; 
    {требуемый всегда} 
       cnum     integer; 
       snum     integer; 
       custnum: integer; 
       salesnum: integer; 
    EXEC SQL END DECLARE SECTION; 
    EXEC SQL DECLARE Wrong_Orders AS CURSOR FOR 
       SELECT cnum, snum 
          FROM Orders a 
          WHERE snum &lt; &gt; 
            (SELECT snum 
                FROM Customers b 
                WHERE a.cnum = b.cnum); 
 
Мы пока еще используем здесь SQL для выполнения основной работы. Запрос выше размещает строки таблицы Порядков которые не согласуются с таблицей Заказчиков.
 
  EXEC SQL DECLARE Cust_assigns AS CURSOR FOR 
     SELECT cnum, snum 
        FROM Customers; 
{Этот курсор используется для получения правильных значений snum}
 
  begin { основная программа } 
EXEC SQL OPEN CURSOR Wrong_Orders; 
while SQLCODE = O do 
{Цикл до тех пор пока Wrong_Orders не опустеет}
 
  begin 
  EXEC SQL FETCH Wrong_Orders INTO 
   (:cnum, :snum); 
  if SQLCODE = O then 
        begin 
{Когда Wrong_Orders опустеет, мы не хотели бы продолжать выполнение этого цикла до бесконечности}
 
  EXEC SQL OPEN CURSOR Cust_Assigns; 
     repeat 
         EXEC SQL FETCH Cust_Assigns 
            INTO (:custnum, :salesnum); 
     until :custnum = :cnum; 
{Повторять FETCH до тех пор пока ... команда будет просматривать Cust_Assigns курсор до строки которая соответствует текущему значению cnum найденного в Wrong_Orders}
 
 
     EXEC SQL CLOSE CURSOR Cust_assigns; 
 
{Поэтому мы будем начинать новый вывод в следующий раз через цикл. Значение в котором мы получим из этого курсора сохраняется в переменной - salesnum.}
 
     EXEC SQL UPDATE Orders 
        SET snum = :salesnum 
        WHERE CURRENT OF Wrong_Orders; 
     end; {Если SQLCODE = 0}. 
  end; 
{ Пока SQLCODE . . . выполнить }
 
EXEC SQL CLOSE CURSOR Wrong_Orders; 
end; { основная программа } 
 
 
2.
Для данной программы которую использовал, решение будет состоять в том, чтобы просто включить поле onum, первичным ключом таблицы Порядков, в курсор Wrong_Orders. В команде UPDATE, вы будете затем использовать предикат WHERE onum =:ordernum ( считая целую переменную - odernum, объявленой), вместо WHERE CURRENT Of Wrong_Orders. Результатом будет программа наподобие этой ( большинство комментариев из предыдущей программы здесь исключены ):
 
 
EXEC SQL BEGIN DECLARE SECTION; 
   SQLCODE:   integer; 
   odernum      integer; 
   cnum         integer; 
   snum         integer; 
   custnum:     integer; 
   salesnum:    integer; 
EXEC SQL END DECLARE SECTION; 
EXEC SQL DECLARE Wrong_Orders AS CURSOR FOR 
   SELECT onum, cnum, snum 
      FROM Orders a 
      WHERE snum &lt; &gt; 
        (SELECT snum 
            FROM Customers b 
WHERE a.cnum = b.cnum); 
EXEC SQL DECLARE Cust _ assigns AS CURSOR FOR 
   SELECT cnum, snum 
      FROM Customers; 
begin { основная программа } 
EXEC SQL OPEN CURSOR Wrong_Orders; 
while SQLCODE = O do {Цикл до тех пор пока Wrong_Orders 
не опустеет} 
   begin 
   EXEC SQL FETCH Wrong_Orders 
      INTO (:odernum, :cnum, :snum); 
   if SQLCODE = O then 
       begin 
       EXEC SQL OPEN CURSOR Cust_Assigns; 
       repeat 
          EXEC SQL FETCH Cust_Assigns 
             INTO (:custnum, :salesnum); 
       until :custnum = :cnum; 
 
       EXEC SQL CLOSE CURSOR Cust_assigns; 
       EXEC SQL UPDATE Orders 
          SET snum = :salesnum 
          WHERE CURRENT OF Wrong_Orders; 
       end; {If SQLCODE = 0} 
    end; { While SQLCODE . . . do } 
EXEC SQL CLOSE CURSOR Wrong_Orders; 
end; { main program } 
 
3. EXEC SQL BEGIN DECLARE SECTION; 
      SQLCODE  integer; 
      newcity      packed array[1. .12] of char; 
      commnull    boolean; 
      citynull     boolean; 
      response    char; 
 
   EXEC SQL END DECLARE SECTION; 
   EXEC SQL DECLARE CURSOR Salesperson AS 
      SELECT * FROM SALESPEOPLE; 
   begln { main program } 
   EXEC SQL OPEN CURSOR Salesperson; 
   EXEC SQL FETCH Salesperson 
      INTO (:snum, :sname, :city:i_cit, :comm:i_com); 
 
{Выборка первой строки} 
while SQLCODE = O do 
{Пока эти строки в таблице Продавцов.} 
      begin 
      if i_com &lt; O then commnull: = true; 
      if i_cit &lt; O then citynull: = true; 
{ Установить логические флаги которые могут показать NULLS.} 
 
      if citynull then 
            begin 
            write  ('Нет текущего значения city для продавца ', 
            snum,   ' Хотите предоставить хотя бы одно? (Y/N)'); 
 
{Подсказка покажет значение city состоящее из NULL значений.} 
 
             read (ответ); 
 
{Ответ может быть сделан позже.} 
 
             end {если конечно - citynull} 
 
      else { не citynull } 
          begin 
          if not commnull then 
 
{ Чтобы выполнять сравнение и операции только для не-NULL значений 
  связи } 
              begin 
              if city = 'London' then comm: = comm * .02 * .02 
                    else comm: = comm + .02; 
              end; 
{Даже если значение и не - commnull, begin и end здесь для ясности.} 
 
         write ('Текущий city для продавца', 
                 snum, 'есть', city, 
                 Хотите его изменить? (Y/N)'); 
 
3.  Обратите Внимание: Продавец не назначенный в данное время 
    в определенный город, не будет иметь изменений комиссионных 
    при определении находится ли он в Лондоне. 
 
    read (ответ); 
 
    {Ответ теперь имеет значение независимо от того что 
     citynull - верен или неверен.} 
 
          end; {иначе не citynull} 
    if response = 'Y' then 
          begin 
          write ('Введите новое значение city:'); 
          read (newcity); 
          if not commnull then 
 
    {Эта операция может быть выполнена только для не-NULL 
     значений. } 
 
              case newcity of: 
                 begin 
                'Barcelona':comm:= comm + .01, 
                'San Jose': comm: = comm *.01 
                 end; {случно и если не commnull} 
          EXEC SQL UPDATE Salespeople 
             SET city = :newcity, comm = :comm:i_com 
             WHERE CURRENT OF Salesperson; 
 
    {Переменна индикатора может поместить NULL значение в поле 
     comm если так назначено.} 
 
             end; { Если ответ = 'Y', или если ответ &lt; &gt; 'Y', 
                    изменений не будет. } 
             EXEC SQL FETCH Salesperson 
                INTO (:snum, :sname, :city:i_clt, 
                 :comm:l_com); 
 
{выборка следующей строки} 
   end; {если SQLCODE = 0} 
   EXEC SQL CLOSE CURSOR Salesperson; 
   end; {основной программы} 
   
</code></pre>
<h2 id="приложение-b">Приложение B</h2>
<h3 id="типы-данных-в-sql">ТИПЫ ДАННЫХ В SQL</h3>
<p>Типы данных распознаваемые с помощью ANSI, состоят из символов и различных типов чисел, которые могут классифицироваться как точные числа и приблизительные числа. Точные числовые типы - это номера, с десятичной точкой или без десятичной точки. Приблизительные числовые типы - это номера в показательной ( экспоненциальной по основанию - 10 ) записи. Для все прочих типов, отличи слишком малы чтобы их как-то классифицировать.
Иногда типы данных используют аргумент, который называю размером аргумента, чей точный формат и значение меняется в зависимости от конкретного типа. Значения по умолчанию обеспечены для всех типов, если размер аргумента отсутствует.</p>
<h4 id="типы-ansi">ТИПЫ ANSI</h4>
<p>Ниже представлены типы данных ANSI ( имена в круглых скобках - это синонимы ):</p>
<h5 id="textтекст">TEXT	ТЕКСТ</h5>
<p>CHAR(или CHARACTER)	Строка текста в реализационно-определенном формате. Размер аргумента здесь это единственное неотрицательное целое число которое ссылается к максимальной длине строки. Значения этого типа, должны быть заключены в одиночные кавычки, например 'text'. Две рядом стоящие одиночные кавычки ('') внутри строки будет пониматься как одна одиночна кавычка (').</p>
<blockquote>
<p>ПРИМЕЧАНИЕ:
Здесь и далее, фраза Реализационно-Определенный или Реализационно-Зависимый, указывает, что этот аргумент или формат зависит от конкретной программы в которой реализуются данные.</p>
</blockquote>
<h5 id="exact-numeric">EXACT NUMERIC</h5>
<p>ТОЧНОЕ ЧИСЛО</p>
<h5 id="dec-или-decimal">DEC (или DECIMAL)</h5>
<p>Десятичное число; то есть, число которое мoжет иметь десятичную точку. Здесь аргумент размера имеет две части: точность и масштаб.Масштаб не может превышать точность. Cначала указывается точность, разделительная запятая и далее аргумент масштаба. Точность указывает сколько значащих цифр имеет число. Максимальное десятичное число составляющее номер - реализационно-определенное значение, равное или большее чем этот номер. Масштаб указывает максимальное число цифр справа от десятичной точки. Масштаб = нулю делает поле эквивалентом целого числа.</p>
<h5 id="numeric">NUMERIC</h5>
<p>Такое же как DECIMAL за исключением того, что максимальное десятичное не может превышать аргумента точности.</p>
<h5 id="int-или-integer">INT( или INTEGER)</h5>
<p>Число без десятичной точки. Эквивалентно DECIMAL, но без цифр справа от десятичной точки, то есть с масштабом равным 0. Аргумент размера не используется (он автоматически устанавливается в реализационно-зависимое значение).</p>
<h5 id="smallint">SMALLINT</h5>
<p>Такое же как INTEGER, за исключением того, что, в зависимости от реализации, размер по умолчанию может ( или не может ) быть меньшее чем INTEGER.</p>
<h5 id="approximate-numeric">APPROXIMATE NUMERIC</h5>
<p>ПРИБЛИЗИТЕЛЬНОЕ ЧИСЛО</p>
<h5 id="float">FLOAT</h5>
<p>Число с плавающей запятой на основе 10 показательной функции. Аргумент размера состоит из одного числа определяющего минимальную точность.</p>
<h5 id="real">REAL</h5>
<p>Такое же как FLOAT, за исключением того, что никакого аргумента размера не используется. Точность установлена реализационно-зависимую по умолчанию.</p>
<h5 id="double-precision--или-double-">DOUBLE PRECISION ( или DOUBLE )</h5>
<p>Такое же как REAL, за исключением того, что реализационно-определяемая точность для DOUBLE PRECISION должна превышать реализационно-определяемую точность REAL.</p>
<h4 id="эквивалентные-типы-данных-в-других-языках">ЭКВИВАЛЕНТНЫЕ ТИПЫ ДАННЫХ В ДРУГИХ ЯЗЫКАХ</h4>
<p>Когда используется вложение SQL в другие языки, значения используемые и произведенные командами SQL, обычно сохраняются в переменных главного языка( см. Главу 25 ). Эти переменные должны иметь тип данных совместимый со значениями SQL, которые они будут получать. В дополнениях, которые не являются частью официального SQL стандарта, ANSI обеспечивает поддержку при использовании вложения SQL в четыре языка: Паскаль, PL/I, КОБОЛ, и ФОРТРАН. Между прочим, он включает определение эквивалентов SQL, для данн- ых типов переменных используемых в этих языках.</p>
<pre><code>Эквиваленты типов данных четырех языков определенных ANSI:
ПЛ/I
SQL ТИП	ЭКВИВАЛЕНТ ПЛ/I
CHAR	CHAR
DECIMAL	FIXED DECIMAL
INTEGER	FIXED BINARY
FLOAT	FLOAT BINARY
КОБОЛ
SQL ТИП	ЭКВИВАЛЕНТ КОБОЛА
CHAR ()	PIC X ()
INTEGER	PIC S () USAGE COMPUTTATIONAL
NUMERIC	PIC S ( &lt; nines with embedded V &gt; ) DISPLAY SING LEADING SEPERATE
ПАСКАЛЬ
SQL ТИП	ЭКВИВАЛЕНТ ПАСКАЛЯ
INTEGER	INTEGER
REAL	REAL
CHAR ()	PACKED ARRAY [1..] OF CHAR
ФОРТРАН
SQL ТИП	ЭКВИВАЛЕНТ ФОРТРАНА
CHAR	CHAR
INTEGER	INTEGER
REAL	REAL
DOUBLE PRECISION	DOUBLE PRECISION
</code></pre>
<h2 id="приложение-c">Приложение C</h2>
<h3 id="некоторые-общие-hестандартные-средства-sql">НЕКОТОРЫЕ ОБЩИЕ HЕСТАНДАРТНЫЕ СРЕДСТВА SQL</h3>
<p>Имеется ряд особенностей языка SQL, которые пока не определены как часть стандарта ANSI или стандарта ISO (Международная Организация По Стандартизации), и являются общими для многочисленных реализаций, так как они были получены для практического использования. Это дополнительные элементы чисел этих особенностей. Конечно, эти особенности меняются от программы к программе, и их обсуждение предназначено только чтобы показать некоторые общие подходы к ним.</p>
<h4 id="tипы-данных">TИПЫ ДАННЫХ</h4>
<p>Типы данных поддерживаемые стандартом SQL, собраны в Приложении B. Это количество для CHARACTER и разнообразие числовых типов. Реализация их может, фактически, быть значительно сложнее чем показано в терминах типов, которые они фактически могут использовать. Мы будем здесь обсуждать ряд таких нестандартных типов данных.</p>
<h4 id="типы-date-и-time">ТИПЫ DATE И TIME</h4>
<p>Как упомянуто в Главе 2, тип данных DATE широко поддерживается, даже если он не часть стандарта. Мы использовали ранее в нашей таблице Порядков, этот тип использующий формат mm/dd/yyyy. Это стандартный формат IBM в США. Разумеется возможны и другие форматы, и программные реализации часто поддерживают ряд форма- тов, позволяя вам выбирать тот который лучше для вас подходит. Реализация которая предлагает эту особенность должна быть способна преобразовывать дату одного формата в другой - автоматически. Имеются несколько основных форматов даты с которыми вы можете столкнуться:</p>
<table>
<thead>
<tr>
<th>Стандарт</th>
<th>Формат</th>
<th>Пример</th>
</tr>
</thead>
<tbody>
<tr>
<td>Международная Организация По Стандартизации</td>
<td>(ISO)</td>
<td>yyyy-mm-dd	1990-10-31</td>
</tr>
<tr>
<td>Японский Индустриальный Стандарт</td>
<td>(JIS)</td>
<td>yyyy-mm-dd	1990-10-31</td>
</tr>
<tr>
<td>IBM Европейский Стандарт</td>
<td>(EUR)</td>
<td>dd.mm.yyyy	10.31.1990</td>
</tr>
</tbody>
</table>
<p>Наличие специального типа определяемого для даты, дает возможность выполнять арифметические операции с датами. Например, вы можете добавлять число дней к дате и получать другую дату, в программе, самостоятельно следящей за числом дней в месяцах, високосными годами, и так далее. Даты могут также сравниваться; например фраза, дата A &lt; дата B , означает, что дата A предшествует дате B по времени. Кроме даты, большое количество программ определяют специальный тип для времени, который может также быть представлен в ряде форматов, включая следующие:</p>
<table>
<thead>
<tr>
<th>Стандарт</th>
<th>Формат</th>
<th>Пример</th>
</tr>
</thead>
<tbody>
<tr>
<td>МЕЖДУНАРОДНАЯ ОРГАНИЗАЦИЯ ПО СТАНДАРТИЗАЦИИ</td>
<td>(ISO)</td>
<td>hh-mm-ss	21.04.37</td>
</tr>
<tr>
<td>Японский Индустриальный Стандарт</td>
<td>(JIS )</td>
<td>hh-mm-ss	21.04.37</td>
</tr>
<tr>
<td>IBM Европейский Стандарт</td>
<td></td>
<td>hh-mm-ss</td>
</tr>
<tr>
<td>IBM USA Стандарт</td>
<td>(USA)</td>
<td>hh.mm AM/PM	9.04 PM</td>
</tr>
</tbody>
</table>
<p>Время может добавляться или сравниваться точно также как дата, с коррекцией числа секунд в минутах или часах автоматически. Кроме того, специально встроенные константы указывающие текущую дату или время ( CURDATE или CURTIME ) являются общими. Они похожи на константу USER (Пользователь) в которой их значение будет непрерывно меняться. Можете ли вы включать врем и дату в одно поле ? Некоторые реализации определяют тип DATE достаточно точно, чтобы включать туда еще и TIME. В качестве альтернативы, третий обобщающий тип, TIMESTAMP, может быть определен как комбинация этих двух.</p>
<h4 id="типы-текстовой-строки">ТИПЫ ТЕКСТОВОЙ СТРОКИ</h4>
<p>ANSI поддерживает только один тип чтобы представлять текст. Это - тип CHAR. Любое поле такого типа должно иметь определенную длину. Если строка вставлена в поле меньше чем длина пол, она дополняется пробелами; строка не может быть длиннее чем длина пол.
Хотя и достаточно удобное, это определение все же имеет некоторые ограничения для пользователя. Например, символьные поля должны иметь одинаковую длину чтобы можно было выполнить команду UNION. Большинство реализаций, поддерживают строки переменной длины для типов данных VARCHAR и LONG VARCHAR( или просто LONG). В то врем как поле типа CHAR всегда может распределить память для максимального числа символов которое может сохраняться в поле, поле VARCHAR при любом количестве символов, может распределить только определенное количество памяти чтобы сохранить фактическое содержание поля, хотя SQL может установить снаружи, некоторое дополнительное пространство памяти чтобы следить за текущей длиной пол. Поле VARCHAR может быть любой длинны включая реализационно-определяемый максимум. Этот максимум может меняться от 254 до 2048 символов для VARCHAR, и до 16000 символов для LONG. LONG обычно используется для текста пояснительного характера или для данных, которые не могут легко сжиматься в простые значения полей; VARCHAR может использоваться для любой текстовой строки чья длина может меняться. Между прочим, не всегда хорошо использовать VARCHAR вместо CHAR. Извлечение и модифицирование полей VARCHAR - более сложный, и следовательно более медленный процесс, чем извлечение и модифицирование полей CHAR. Кроме того, некоторое количество памяти VARCHAR, остается всегда неиспользованной (в резерве) для гарантии вмещения всей длины строки. Вы должны просчитывать, насколько значения полей могут меняться по длине, а также, способны ли они к объединению с другими полями, перед тем как решить, использовать CHAR или VARCHAR. Часто, тип LONG используется для сохранения двоичных данных. Естественно, что использование размера такого &quot;неуклюжего&quot; пол будет ограничивать оперативность SQL. Проконсультируйтесь с вашим руководством.</p>
<h4 id="команда-format">КОМАНДА FORMAT</h4>
<p>Как мы подчеркивали в Главе 7, процесс вывода выполняемого в стандарте SQL - ограничен. Хотя большинство реализаций включают SQL в пакеты, имеющие другие средства для управления этой функцией, некоторые реализации также используют команду типа FORMAT внутри SQL чтобы навзывать выводу запроса, определенные формы, структуры, или ограничения. Среди возможных функций команды FORMAT - существуют такие:</p>
<ul>
<li>определение ширины столбцов ( при печати ).</li>
<li>oпределение представления NULL значений.</li>
<li>обеспечение (новых) заголовков для столбцов.
обеспечение заголовков внизу или вверху страниц выводимых на печать.</li>
<li>навязывает присвоение или изменение форматам полей содержащих значения даты, времени или денежной суммы.</li>
<li>вычисляет общие и промежуточные суммы не исключая возможности обобщения поля, как это делает например SUM.
(Альтернативным подходом к этой проблеме в некоторых программах является предложение COMPUTE.)</li>
</ul>
<p>Команда FORMAT может вводиться сразу перед или сразу после запроса к которому она применяется, в зависимости от реализации. Одна команда FORMAT обычно может применяться только к одному запросу, хотя любое число команд FORMAT может применяться к одному и тому же запросу. Вот некоторые примеры команды FORMAT:</p>
<pre><code>   FORMAT NULL '_ _ _ _ _ _ _'; 
   FORMAT BTITLE 'Orders Grouped by Salesperson';
   FORMAT EXCLUDE (2, 3);
</code></pre>
<p>Первая из их значения NULL представляется в виде ' _ _ _ _ _ _ _ ' при выводе на печать; вторая вставляет заголовок 'Orders Grouped by Salesperson' в нижнюю часть каждой страницы; треть исключает второй и третий столбцы из вывода предыдущего запроса. Вы могли бы использовать последнюю из их если вы выбираете конкретные столбцы, чтобы использовать их в предложении ORDER BY, в вашем выводе. Так как указанные функции команды FORMAT могут выполняться по разному, весь набор их приложений не может быть здесь показан.</p>
<p>Имеются другие команды которые могут использоваться для выполнения тех же функций. Команда SET подобна команде FORMAT; она является вариантом или дополнением к команде, которая применяется во всех запросах текущего сеанса пользователя а не просто в одиночном запросе. В следующей реализации, команда FORMAT начинается ключевым словом COLUMN следующим образом:</p>
<pre><code>COLUMN odate FORMAT dd-mon-yy;
</code></pre>
<p>что навязывает формат типа - 10-Oct-90 в поле даты использующемся в выводе запроса на печать. Предложение COMPUTE, упомянутое ранее, вставляется в запрос, следующим образом:</p>
<pre><code>    SELECT odate, amt
       FROM Orders 
       WHERE snum = 1001
       COMPUTE SUM (amt); 
</code></pre>
<p>Оно выводит все порядки продавца Peel, с датой и суммой приобретения по каждой дате, а в конце, общую сумму приобретений. Другая реализация выводит промежуточные суммы приобретений используя COMPUTE в качестве команды. Сначала, она определяет разбивку</p>
<pre><code>        BREAK ON odate; 
</code></pre>
<p>вывода вышеупомянутого запроса на страницы - сгруппировав их по датам, поэтому все значения odate в каждой группе - одинаковые. Затем вы можете ввести следующее предложение:</p>
<pre><code>       COMPUTE SUM OF amt ON odate;
</code></pre>
<p>Столбец в предложении ON, предварительно, должен быть использован в команде BREAK.</p>
<h4 id="функции">ФУНКЦИИ</h4>
<p>Для SQL в стандарте ANSI, вы можете применять агрегатные функции для столбцов или использовать их значения в скалярных выражениях,таких например как - comm * 100. Имеется много других полезных функций, которые вы, вероятно встречали на практике.</p>
<p>Имеется список некоторых общих функций SQL отличающихся от стандартных агрегатов. Они могут использоваться в предложениях SELECT запросов, точно так же как агрегатные функции, но эти функции выполняются для одиночных значений а не групповых. В следующем списке они классифицированы согласно типам данных с которыми они выполняются. Если нет примечаний, то переменные в этом списке стандартизированы для любого выражения значений соответствующего типа, которые могут быть использованы в предложении SELECT:</p>
<h5 id="математические-функции">МАТЕМАТИЧЕСКИЕ ФУНКЦИИ</h5>
<p>Эти функции применяются для чисел.</p>
<table>
<thead>
<tr>
<th>ФУНКЦИЯ</th>
<th>ЗНАЧЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>ABX(X)</td>
<td>Абсолютное значение из X ( преобразование отрицательного или положительного значений в положительное )</td>
</tr>
<tr>
<td>CEIL (X)</td>
<td>X - является десятичным значением которое будет округляться сверху.</td>
</tr>
<tr>
<td>FLOOR (X)</td>
<td>X - является десятичным значением которое будет округляться снизу.</td>
</tr>
<tr>
<td>GREATEST(X,Y)</td>
<td>Возвращает большее из двух значений.</td>
</tr>
<tr>
<td>LEAST(X,Y)</td>
<td>Возвращает меньшее из двух значений.</td>
</tr>
<tr>
<td>MOD(X,Y)</td>
<td>Возвращает остаток от деления X на Y.</td>
</tr>
<tr>
<td>POWER(X,Y)</td>
<td>Возвращает значение X в степени Y.</td>
</tr>
<tr>
<td>ROUND(X,Y)</td>
<td>Цикл от X до десятичного Y. Eсли Y отсутствует, цикл до целого числа.</td>
</tr>
<tr>
<td>SING(X)</td>
<td>Bозвращает минус если X &lt; 0, или плюс если X &gt; 0.</td>
</tr>
<tr>
<td>SQRT (X)</td>
<td>Возвращает квадратный корень из X.</td>
</tr>
</tbody>
</table>
<h5 id="символьные-функции">СИМВОЛЬНЫЕ ФУНКЦИИ</h5>
<p>Эти функции могут быть применены для строк текста, либо из столбцов текстовых типов данных, либо из строк литерных текстов, или же комбинация из этих двух.</p>
<table>
<thead>
<tr>
<th>ФУНКЦИЯ</th>
<th>ЗНАЧЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>LEFT(,X)</td>
<td>Возвращает крайние левые(старшие) символы X из строки.</td>
</tr>
<tr>
<td>RICHT(,X)</td>
<td>Возвращает символы X младшего разряда из строки</td>
</tr>
<tr>
<td>ASCII()</td>
<td>Возвращает код ASCII которым представляется строка в памяти компьютера.</td>
</tr>
<tr>
<td>CHR()</td>
<td>Возвращает принтерные символы кода ASCII.</td>
</tr>
<tr>
<td>VALUE()</td>
<td>Возвращает математическое значение для строки. Считается что строка имеет тип CHAR или VARCHAR, но состоит из чисел. VALUE('3')</td>
</tr>
<tr>
<td>UPPER()</td>
<td>Преобразует все символы строки в символы верхнего регистра.</td>
</tr>
<tr>
<td>LOWER()</td>
<td>Преобразует все символы строки в символы нижнего регистра.</td>
</tr>
<tr>
<td>INlTCAP()</td>
<td>Преобразует символы строки в заглавные буквы. В некоторых реализациях может иметь название - PROPER.</td>
</tr>
<tr>
<td>LENGTH()</td>
<td>Возвращает число символов в строке.</td>
</tr>
<tr>
<td>\</td>
<td>\</td>
</tr>
<tr>
<td>LPAD(,X,'*' )</td>
<td>Дополняет строку слева звездочками '*', или любым другим указанным символом, с количестве, определяем ом X.</td>
</tr>
<tr>
<td>RPAD(,X, &quot;)</td>
<td>То же самое что и LPAD, за исключением того, что дополнение делается справа.</td>
</tr>
<tr>
<td>SUBSTR(,X,Y)</td>
<td>Извлекает Y символов из строки начиная с позиции X.</td>
</tr>
</tbody>
</table>
<h5 id="функции-даты-и-времени">ФУНКЦИИ ДАТЫ И ВРЕМЕНИ</h5>
<p>Эти функции выполняются только для допустимых значений даты или времени.</p>
<table>
<thead>
<tr>
<th>ФУНКЦИЯ</th>
<th>ЗНАЧЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>DAY()</td>
<td>Извлекает день месяца из даты. Подобные же функции существуют для MONTH(МЕСЯЦ), YEAR(ГОД), HOUR(ЧАСЫ), SECOND(СЕКУНДЫ) и так далее.</td>
</tr>
<tr>
<td>WEEKDAY()</td>
<td>Извлекает день недели из даты.</td>
</tr>
</tbody>
</table>
<h5 id="другие-функции">ДРУГИЕ ФУНКЦИИ</h5>
<p>Эта функция может быть применена к любому типу данных.</p>
<table>
<thead>
<tr>
<th>ФУНКЦИЯ</th>
<th>ЗНАЧЕНИЕ</th>
</tr>
</thead>
<tbody>
<tr>
<td>NVL(,)</td>
<td>NVL (NULL Значение) будет меняться на значение каждое NULL значение найденное в столбце . Если полученное значение не =NULL, NVL ничего не делает.</td>
</tr>
</tbody>
</table>
<h5 id="intersect-и-minus">INTERSECT И MINUS</h5>
<p>Команда UNION, как вы уже видели в Главе 14, может объединить два запроса, объединив их вывод в один. Два других обычно имеющихся способа объединения отдельных запросов - это INTERSECT(Плюс) и MINUS(Минус). INTERSECT выводит только строки произведенные обоими перекрестными запросами, в то врем как MINUS выводит строки которые производятся одним запросом, но не другим. Следовательно, следующие два запроса</p>
<pre><code>  SELECT * 
     FROM Salespeople
     WHERE city = 'London' 

     INTERSECT 

  SELECT * 
     FROM Salespeople 
     WHERE 'London' IN 
        (SELECT city 
            FROM Customers 
            WHERE Customers.snum = 
             Salespeople.snum); 
</code></pre>
<p>выведут строки произведенные обоими запросами, производящими всех продавцов в Лондоне которые имели по крайней мере одного заказчика размещенного там также. С другой стороны, запрос
SELECT *
FROM Salespeople
WHERE city = 'London'</p>
<pre><code>     MINUS 

  SELECT * 
     FROM Salespeople 
     WHERE 'London' IN 
        (SELECT sity 
            FROM Customers 
            WHERE Customers.snum = 
             Salespeople.snum); 
</code></pre>
<p>удалит строки выбранные вторым запросом из вывода первого, и таким образом будут выведены все продавцы в Лондоне которые не имели там заказчиков. MINUS иногда еще называют DIFFERENCE (ОТЛИЧИЕ)</p>
<h4 id="автоматические-внешние-объединения">АВТОМАТИЧЕСКИЕ ВНЕШНИЕ ОБЪЕДИНЕНИЯ</h4>
<p>В Главе 14, мы обсуждали внешнее объединение и показывали вам как выполнять его используя команду UNION. Некоторые программы базы данных имеют более непосредственный способ выполнения внешних объединений. В некоторых реализациях, вводимый знак &quot; + &quot; после предиката, может выводить строки которые удовлетворяют условию также как и строки которые ему не удовлетворяют. В условии предиката может содержаться поле совпадающее для обеих таблиц, и NULL значения будут вставлены там, где такого совпадения не будет найдено. Например, предположим вы хотите видеть ваших продавцов и соответствующих им заказчиков, не исключая тех продавцов которым не назначено ни одного заказчика ( хотя такого нет в наших типовых таблицах, но в действительности это возможно ) :</p>
<pre><code>    SELECT a.snum, sname, cname 
       FROM Salespeople a, Customers b 
       WHEREa.snum = b.snum(+); 
</code></pre>
<p>Это является эквивалентом следующего объединения (UNION):</p>
<pre><code>    SELECT a.snum, sname, cname 
       FROM Salespeople a, Customers b 
       WHERE a.snum = b.snum 

       UNION 

    SELECT snum, sname, '_ _ _ _ _ _ _ _ _ _' 
       FROM Salespeople 
       WHERE snum NOT IN 
          (SELECT snum 
              FROM Customers); 
</code></pre>
<p>Мы считаем что подчеркивания будут отображены NULL значениями( см. команду FORMAT ранее в этом приложении где описывалось отображение NULL значениями).</p>
<h4 id="отслеживание-действий">ОТСЛЕЖИВАНИЕ ДЕЙСТВИЙ</h4>
<p>Ваша SQL реализация - достаточна хороша, если она доступна многим пользователям, чтобы обеспечивать для них некий способ слежения за действиями выполняемыми в базе данных. Имеются две основные формы чтобы делать это:</p>
<pre><code>Journaling(Протоколирование) и  Auditing(Ревизия). 
</code></pre>
<p>Эти формы отличаются по назначению.
Journaling, применяется с целью защиты ваших данных, при разрушении вашей системы. Сначала Вы используете реализационно-зависимую процедуру чтобы архивировать текущее содержание вашей базы данных, поэтому копия ее содержания где-нибудь будет сохранена. Затем вы просматриваете протокол изменений сделанных в базе данных. Он сохраняется в некоторой области памяти, но не в главной памяти базы данных, а желательно на отдельном устройстве, и содержит список всех команд которые произвели изменения в структуре или в содержании базы данных. Если у вас вдруг появились проблемы и текущее содержание вашей базы данных оказалось нарушенным, вы можете повторно выполнить все изменения зарегистрированные в протоколе на резервной копии ва шей базы данных, и снова привести вашу базу данных в состояние которое было до момента последней записи в протокол. Типичной командой, чтобы начать протоколирование, будет следующая:</p>
<pre><code>SET JOURNAL ON; 
</code></pre>
<p>Auditing используется c целью защиты. Она следит за тем, кто и какие действия выполнял в базе данных, и сохраняет эту информацию в таблице доступной только очень немногим высоко привилегированным пользователям. Конечно, вы редко будете прибегать к процедуре ревизии, потому что очень скоро она займет много памяти и вам будет сложно работать в вашей базе данных. Но вы можете устанавливать ревизию для опре- деленных пользователей, определенных действий или определенных объектов данных. Имеется такая форма команды AUDIT:</p>
<pre><code>AUDIT INSERT ON Salespeople BY Diane; 
</code></pre>
<p>Или предложение ON или предложение BY могут быть исключены, устанавливая ревизию, либо всех объектов или всех пользователей, соответственно. Применение AUDIT ALL, вместо AUDIT INSERT, приведет к отслеживанию всех действий Diane в таблице Продавцов.</p>
<h2 id="приложение-e">Приложение E</h2>
<h3 id="таблицы-используемые-в-sql">ТАБЛИЦЫ, ИСПОЛЬЗУЕМЫЕ В SQL</h3>
<p>====================  ТАБЛИЦА 1:  ПРОДАВЦЫ  ================</p>
<pre><code>  ---------------------------------------------- 
    snum  |   sname   |  city        |   comm 
  --------|-----------|--------------|---------- 
    1001  |  Peel     |  London      |    .12 
    1002  |  Serres   |  San Jose    |    .13 
    1004  |  Motika   |  London      |    .11 
    1007  |  Rifkin   |  Barcelona   |    .15 
    1003  |  Axelrod  |  New York    |    .10 
   --------------------------------------------- 
</code></pre>
<p>==================  ТАБЛИЦА 2:  ЗАКАЗЧИКИ  ===============</p>
<pre><code>   ---------------------------------------------- 
    cnum  |  cname     | city    | rating | snum 
   -------|------------|---------|--------|------ 
    2001  |  Hoffman   | London  |   100  | 1001 
    2002  |  Giovanni  | Rome    |   200  | 1003 
    2003  |  Liu       | SanJose |   200  | 1002 
    2004  |  Grass     | Berlin  |   300  | 1002 
    2006  |  Clemens   | London  |   100  | 1001 
    2008  |  Cisneros  | SanJose |   300  | 1007 
    2007  |  Pereira   | Rome    |   100  | 1004 
   ---------------------------------------------- 
</code></pre>
<p>==================  ТАБЛИЦА 3:   ПОРЯДКИ  ==================</p>
<pre><code>   ----------------------------------------------- 
    onum  |    amt    |    odate    | cnum | snum 
   -------|-----------|-------------|------|------ 
    3001  |    18.69  |  10/03/1990 | 2008 | 1007 
    3003  |   767.19  |  10/03/1990 | 2001 | 1001 
    3002  |  1900.10  |  10/03/1990 | 2007 | 1004 
    3005  |  5160.45  |  10/03/1990 | 2003 | 1002 
    3006  |  1098.16  |  10/03/1990 | 2008 | 1007 
    3009  |  1713.23  |  10/04/1990 | 2002 | 1003 
    3007  |    75.75  |  10/04/1990 | 2004 | 1002 
    3008  |  4723.00  |  10/05/1990 | 2006 | 1001 
    3010  |  1309.95  |  10/06/1990 | 2004 | 1002 
    3011  |  9891.88  |  10/06/1990 | 2006 | 1001 
   ----------------------------------------------- 
</code></pre>

    <!-- End Markdown Monster Content -->
</div>
</body>
</html>
